<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Interactive BOM for KiCAD</title>
  <style type="text/css">
:root {
  --pcb-edge-color: black;
  --pad-color: #878787;
  --pad-hole-color: #CCCCCC;
  --pad-color-highlight: #D04040;
  --pin1-outline-color: #ffb629;
  --pin1-outline-color-highlight: #b4ff03;
  --silkscreen-edge-color: #aa4;
  --silkscreen-polygon-color: #4aa;
  --silkscreen-text-color: #4aa;
  --fabrication-edge-color: #907651;
  --fabrication-polygon-color: #907651;
  --fabrication-text-color: #a27c24;
  --track-color: #def5f1;
  --track-color-highlight: #D04040;
  --zone-color: #def5f1;
  --zone-color-highlight: #d0404080;
}

html, body {
  margin: 0px;
  height: 100%;
  font-family: Verdana, sans-serif;
}

.dark.topmostdiv {
  --pcb-edge-color: #eee;
  --pad-color: #808080;
  --pin1-outline-color: #ffa800;
  --pin1-outline-color-highlight: #ccff00;
  --track-color: #42524f;
  --zone-color: #42524f;
  background-color: #252c30;
  color: #eee;
}

button {
  background-color: #eee;
  border: 1px solid #888;
  color: black;
  height: 44px;
  width: 44px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 14px;
  font-weight: bolder;
}

.dark button {
  /* This will be inverted */
  background-color: #c3b7b5;
}

button.depressed {
  background-color: #0a0;
  color: white;
}

.dark button.depressed {
  /* This will be inverted */
  background-color: #b3b;
}

button:focus {
  outline: 0;
}

button#tb-btn {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8.47 8.47'%3E%3Crect transform='translate(0 -288.53)' ry='1.17' y='288.8' x='.27' height='7.94' width='7.94' fill='%23f9f9f9'/%3E%3Cg transform='translate(0 -288.53)'%3E%3Crect width='7.94' height='7.94' x='.27' y='288.8' ry='1.17' fill='none' stroke='%23000' stroke-width='.4' stroke-linejoin='round'/%3E%3Cpath d='M1.32 290.12h5.82M1.32 291.45h5.82' fill='none' stroke='%23000' stroke-width='.4'/%3E%3Cpath d='M4.37 292.5v4.23M.26 292.63H8.2' fill='none' stroke='%23000' stroke-width='.3'/%3E%3Ctext font-weight='700' font-size='3.17' font-family='sans-serif'%3E%3Ctspan x='1.35' y='295.73'%3EF%3C/tspan%3E%3Ctspan x='5.03' y='295.68'%3EB%3C/tspan%3E%3C/text%3E%3C/g%3E%3C/svg%3E%0A");
}

button#lr-btn {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8.47 8.47'%3E%3Crect transform='translate(0 -288.53)' ry='1.17' y='288.8' x='.27' height='7.94' width='7.94' fill='%23f9f9f9'/%3E%3Cg transform='translate(0 -288.53)'%3E%3Crect width='7.94' height='7.94' x='.27' y='288.8' ry='1.17' fill='none' stroke='%23000' stroke-width='.4' stroke-linejoin='round'/%3E%3Cpath d='M1.06 290.12H3.7m-2.64 1.33H3.7m-2.64 1.32H3.7m-2.64 1.3H3.7m-2.64 1.33H3.7' fill='none' stroke='%23000' stroke-width='.4'/%3E%3Cpath d='M4.37 288.8v7.94m0-4.11h3.96' fill='none' stroke='%23000' stroke-width='.3'/%3E%3Ctext font-weight='700' font-size='3.17' font-family='sans-serif'%3E%3Ctspan x='5.11' y='291.96'%3EF%3C/tspan%3E%3Ctspan x='5.03' y='295.68'%3EB%3C/tspan%3E%3C/text%3E%3C/g%3E%3C/svg%3E%0A");
}

button#bom-btn {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8.47 8.47'%3E%3Crect transform='translate(0 -288.53)' ry='1.17' y='288.8' x='.27' height='7.94' width='7.94' fill='%23f9f9f9'/%3E%3Cg transform='translate(0 -288.53)' fill='none' stroke='%23000' stroke-width='.4'%3E%3Crect width='7.94' height='7.94' x='.27' y='288.8' ry='1.17' stroke-linejoin='round'/%3E%3Cpath d='M1.59 290.12h5.29M1.59 291.45h5.33M1.59 292.75h5.33M1.59 294.09h5.33M1.59 295.41h5.33'/%3E%3C/g%3E%3C/svg%3E");
}

button#bom-grouped-btn {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cg stroke='%23000' stroke-linejoin='round' class='layer'%3E%3Crect width='29' height='29' x='1.5' y='1.5' stroke-width='2' fill='%23fff' rx='5' ry='5'/%3E%3Cpath stroke-linecap='square' stroke-width='2' d='M6 10h4m4 0h5m4 0h3M6.1 22h3m3.9 0h5m4 0h4m-16-8h4m4 0h4'/%3E%3Cpath stroke-linecap='null' d='M5 17.5h22M5 26.6h22M5 5.5h22'/%3E%3C/g%3E%3C/svg%3E");
}

button#bom-ungrouped-btn {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cg stroke='%23000' stroke-linejoin='round' class='layer'%3E%3Crect width='29' height='29' x='1.5' y='1.5' stroke-width='2' fill='%23fff' rx='5' ry='5'/%3E%3Cpath stroke-linecap='square' stroke-width='2' d='M6 10h4m-4 8h3m-3 8h4'/%3E%3Cpath stroke-linecap='null' d='M5 13.5h22m-22 8h22M5 5.5h22'/%3E%3C/g%3E%3C/svg%3E");
}

button#bom-netlist-btn {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cg fill='none' stroke='%23000' class='layer'%3E%3Crect width='29' height='29' x='1.5' y='1.5' stroke-width='2' fill='%23fff' rx='5' ry='5'/%3E%3Cpath stroke-width='2' d='M6 26l6-6v-8m13.8-6.3l-6 6v8'/%3E%3Ccircle cx='11.8' cy='9.5' r='2.8' stroke-width='2'/%3E%3Ccircle cx='19.8' cy='22.8' r='2.8' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E");
}

button#copy {
  background-image: url("data:image/svg+xml,%3Csvg height='48' viewBox='0 0 48 48' width='48' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h48v48h-48z' fill='none'/%3E%3Cpath d='M32 2h-24c-2.21 0-4 1.79-4 4v28h4v-28h24v-4zm6 8h-22c-2.21 0-4 1.79-4 4v28c0 2.21 1.79 4 4 4h22c2.21 0 4-1.79 4-4v-28c0-2.21-1.79-4-4-4zm0 32h-22v-28h22v28z'/%3E%3C/svg%3E");
  background-position: 6px 6px;
  background-repeat: no-repeat;
  background-size: 26px 26px;
  border-radius: 6px;
  height: 40px;
  width: 40px;
  margin: 10px 5px;
}

button#copy:active {
    box-shadow: inset 0px 0px 5px #6c6c6c;
}

textarea.clipboard-temp {
  position: fixed;
  top: 0;
  left: 0;
  width: 2em;
  height: 2em;
  padding: 0;
  border: None;
  outline: None;
  box-shadow: None;
  background: transparent;
}

.left-most-button {
  border-right: 0;
  border-top-left-radius: 6px;
  border-bottom-left-radius: 6px;
}

.middle-button {
  border-right: 0;
}

.right-most-button {
  border-top-right-radius: 6px;
  border-bottom-right-radius: 6px;
}

.button-container {
  font-size: 0;
  margin: 10px 10px 10px 0px;
}

.dark .button-container {
  filter: invert(1);
}

.button-container button {
  background-size: 32px 32px;
  background-position: 5px 5px;
  background-repeat: no-repeat;
}

@media print {
  .hideonprint {
    display: none;
  }
}

canvas {
  cursor: crosshair;
}

canvas:active {
  cursor: grabbing;
}

.fileinfo {
  width: 100%;
  max-width: 1000px;
  border: none;
  padding: 5px;
}

.fileinfo .title {
  font-size: 20pt;
  font-weight: bold;
}

.fileinfo td {
  overflow: hidden;
  white-space: nowrap;
  max-width: 1px;
  width: 50%;
  text-overflow: ellipsis;
}

.bom {
  border-collapse: collapse;
  font-family: Consolas, "DejaVu Sans Mono", Monaco, monospace;
  font-size: 10pt;
  table-layout: fixed;
  width: 100%;
  margin-top: 1px;
}

.bom th, .bom td {
  border: 1px solid black;
  padding: 5px;
  word-wrap: break-word;
  text-align: center;
  position: relative;
}

.dark .bom th, .dark .bom td {
  border: 1px solid #777;
}

.bom th {
  background-color: #CCCCCC;
  background-clip: padding-box;
}

.dark .bom th {
  background-color: #3b4749;
}

.bom tr.highlighted:nth-child(n) {
  background-color: #cfc;
}

.dark .bom tr.highlighted:nth-child(n) {
  background-color: #226022;
}

.bom tr:nth-child(even) {
  background-color: #f2f2f2;
}

.dark .bom tr:nth-child(even) {
  background-color: #313b40;
}

.bom tr.checked {
  color: #aaa;
}

.dark .bom tr.checked {
  color: #666;
}

.bom tr {
  transition: background-color 0.2s;
}

.bom .numCol {
  width: 25px;
}

.bom .Description {
  width: 10%;
}

.bom .Part {
  width: 10%;
}

.bom .Value {
  width: 15%;
}

.bom .Quantity {
  width: 65px;
}

.bom th .sortmark {
  position: absolute;
  right: 1px;
  top: 1px;
  margin-top: -5px;
  border-width: 5px;
  border-style: solid;
  border-color: transparent transparent #221 transparent;
  transform-origin: 50% 85%;
  transition: opacity 0.2s, transform 0.4s;
}

.dark .bom th .sortmark {
  filter: invert(1);
}

.bom th .sortmark.none {
  opacity: 0;
}

.bom th .sortmark.desc {
  transform: rotate(180deg);
}

.bom th:hover .sortmark.none {
  opacity: 0.5;
}

.bom .bom-checkbox {
  width: 30px;
  position: relative;
  user-select: none;
  -moz-user-select: none;
}

.bom .bom-checkbox:before {
  content: "";
  position: absolute;
  border-width: 15px;
  border-style: solid;
  border-color: #51829f transparent transparent transparent;
  visibility: hidden;
  top: -15px;
}

.bom .bom-checkbox:after {
  content: "Double click to set/unset all";
  position: absolute;
  color: white;
  top: -35px;
  left: -26px;
  background: #51829f;
  padding: 5px 15px;
  border-radius: 8px;
  white-space: nowrap;
  visibility: hidden;
}

.bom .bom-checkbox:hover:before, .bom .bom-checkbox:hover:after {
  visibility: visible;
  transition: visibility 0.2s linear 1s;
}

.split {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  overflow-y: auto;
  overflow-x: hidden;
  background-color: inherit;
}

.split.split-horizontal, .gutter.gutter-horizontal {
  height: 100%;
  float: left;
}

.gutter {
  background-color: #ddd;
  background-repeat: no-repeat;
  background-position: 50%;
  transition: background-color 0.3s;
}

.dark .gutter {
  background-color: #777;
}

.gutter.gutter-horizontal {
  background-image: url('');
  cursor: ew-resize;
  width: 5px;
}

.gutter.gutter-vertical {
  background-image: url('');
  cursor: ns-resize;
  height: 5px;
}

.searchbox {
  float: left;
  height: 40px;
  margin: 10px 5px;
  padding: 12px 32px;
  font-family: Consolas, "DejaVu Sans Mono", Monaco, monospace;
  font-size: 18px;
  box-sizing: border-box;
  border: 1px solid #888;
  border-radius: 6px;
  outline: none;
  background-color: #eee;
  transition: background-color 0.2s, border 0.2s;
  background-image: url('');
  background-position: 10px 10px;
  background-repeat: no-repeat;
}

.dark .searchbox {
  background-color: #111;
  color: #eee;
}

.searchbox::placeholder {
  color: #ccc;
}

.dark .searchbox::placeholder {
  color: #666;
}

.filter {
  width: calc(60% - 64px);
}

.reflookup {
  width: calc(40% - 10px);
}

input[type=text]:focus {
  background-color: white;
  border: 1px solid #333;
}

.dark input[type=text]:focus {
  background-color: #333;
  border: 1px solid #ccc;
}

mark.highlight {
  background-color: #5050ff;
  color: #fff;
  padding: 2px;
  border-radius: 6px;
}

.dark mark.highlight {
  background-color: #76a6da;
  color: #111;
}

.menubtn {
  background-color: white;
  border: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='36' viewBox='0 0 20 20'%3E%3Cpath fill='none' d='M0 0h20v20H0V0z'/%3E%3Cpath d='M15.95 10.78c.03-.25.05-.51.05-.78s-.02-.53-.06-.78l1.69-1.32c.15-.12.19-.34.1-.51l-1.6-2.77c-.1-.18-.31-.24-.49-.18l-1.99.8c-.42-.32-.86-.58-1.35-.78L12 2.34c-.03-.2-.2-.34-.4-.34H8.4c-.2 0-.36.14-.39.34l-.3 2.12c-.49.2-.94.47-1.35.78l-1.99-.8c-.18-.07-.39 0-.49.18l-1.6 2.77c-.1.18-.06.39.1.51l1.69 1.32c-.04.25-.07.52-.07.78s.02.53.06.78L2.37 12.1c-.15.12-.19.34-.1.51l1.6 2.77c.1.18.31.24.49.18l1.99-.8c.42.32.86.58 1.35.78l.3 2.12c.04.2.2.34.4.34h3.2c.2 0 .37-.14.39-.34l.3-2.12c.49-.2.94-.47 1.35-.78l1.99.8c.18.07.39 0 .49-.18l1.6-2.77c.1-.18.06-.39-.1-.51l-1.67-1.32zM10 13c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3z'/%3E%3C/svg%3E%0A");
  background-position: center;
  background-repeat: no-repeat;
}

.statsbtn {
  background-color: white;
  border: none;
  background-image: url("data:image/svg+xml,%3Csvg width='36' height='36' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M4 6h28v24H4V6zm0 8h28v8H4m9-16v24h10V5.8' fill='none' stroke='%23000' stroke-width='2'/%3E%3C/svg%3E");
  background-position: center;
  background-repeat: no-repeat;
}

.iobtn {
  background-color: white;
  border: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='36' height='36'%3E%3Cpath fill='none' stroke='%23000' stroke-width='2' d='M3 33v-7l6.8-7h16.5l6.7 7v7H3zM3.2 26H33M21 9l5-5.9 5 6h-2.5V15h-5V9H21zm-4.9 0l-5 6-5-6h2.5V3h5v6h2.5z'/%3E%3Cpath fill='none' stroke='%23000' d='M6.1 29.5H10'/%3E%3C/svg%3E");
  background-position: center;
  background-repeat: no-repeat;
}

.dark .statsbtn, .dark .savebtn, .dark .menubtn, .dark .iobtn {
  filter: invert(1);
}

.flexbox {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
}

.savebtn {
  background-color: #d6d6d6;
  width: auto;
  height: 30px;
  flex-grow: 1;
  margin: 5px;
  border-radius: 4px;
}

.savebtn:active {
  background-color: #0a0;
  color: white;
}

.dark .savebtn:active {
  /* This will be inverted */
  background-color: #b3b;
}

.stats {
  border-collapse: collapse;
  font-size: 12pt;
  table-layout: fixed;
  width: 100%;
  min-width: 450px;
}

.dark .stats td {
  border: 1px solid #bbb;
}

.stats td {
  border: 1px solid black;
  padding: 5px;
  word-wrap: break-word;
  text-align: center;
  position: relative;
}

#checkbox-stats div {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

#checkbox-stats .bar {
  background-color: rgba(28, 251, 0, 0.6);
}

.menu {
  position: relative;
  display: inline-block;
  margin: 10px 10px 10px 0px;
}

.menu-content {
  display: none;
  position: absolute;
  background-color: white;
  right: 0;
  min-width: 300px;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 100;
  padding: 8px;
}

.dark .menu-content {
  background-color: #111;
}

.menu:hover .menu-content {
  display: block;
}

.menu:hover .menubtn, .menu:hover .iobtn, .menu:hover .statsbtn {
  background-color: #eee;
}

.menu-label {
  display: inline-block;
  padding: 8px;
  border: 1px solid #ccc;
  border-top: 0;
  width: calc(100% - 18px);
}

.menu-label-top {
  border-top: 1px solid #ccc;
}

.menu-textbox {
  float: left;
  height: 24px;
  margin: 10px 5px;
  padding: 5px 5px;
  font-family: Consolas, "DejaVu Sans Mono", Monaco, monospace;
  font-size: 14px;
  box-sizing: border-box;
  border: 1px solid #888;
  border-radius: 4px;
  outline: none;
  background-color: #eee;
  transition: background-color 0.2s, border 0.2s;
  width: calc(100% - 10px);
}

.menu-textbox.invalid, .dark .menu-textbox.invalid {
  color: red;
}

.dark .menu-textbox {
  background-color: #222;
  color: #eee;
}

.radio-container {
  margin: 4px;
}

.topmostdiv {
  width: 100%;
  height: 100%;
  background-color: white;
  transition: background-color 0.3s;
}

#top {
  height: 78px;
  border-bottom: 2px solid black;
}

.dark #top {
  border-bottom: 2px solid #ccc;
}

#dbg {
  display: block;
}

::-webkit-scrollbar {
  width: 8px;
}

::-webkit-scrollbar-track {
  background: #aaa;
}

::-webkit-scrollbar-thumb {
  background: #666;
  border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
  background: #555;
}

.slider {
  -webkit-appearance: none;
  width: 100%;
  margin: 3px 0;
  padding: 0;
  outline: none;
  opacity: 0.7;
  -webkit-transition: .2s;
  transition: opacity .2s;
  border-radius: 3px;
}

.slider:hover {
  opacity: 1;
}

.slider:focus {
  outline: none;
}

.slider::-webkit-slider-runnable-track {
  -webkit-appearance: none;
  width: 100%;
  height: 8px;
  background: #d3d3d3;
  border-radius: 3px;
  border: none;
}

.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: #0a0;
  cursor: pointer;
  margin-top: -4px;
}

.dark .slider::-webkit-slider-thumb {
  background: #3d3;
}

.slider::-moz-range-thumb {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: #0a0;
  cursor: pointer;
}

.slider::-moz-range-track {
  height: 8px;
  background: #d3d3d3;
  border-radius: 3px;
}

.dark .slider::-moz-range-thumb {
  background: #3d3;
}

.slider::-ms-track {
  width: 100%;
  height: 8px;
  border-width: 3px 0;
  background: transparent;
  border-color: transparent;
  color: transparent;
  transition: opacity .2s;
}

.slider::-ms-fill-lower {
  background: #d3d3d3;
  border: none;
  border-radius: 3px;
}

.slider::-ms-fill-upper {
  background: #d3d3d3;
  border: none;
  border-radius: 3px;
}

.slider::-ms-thumb {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background: #0a0;
  cursor: pointer;
  margin: 0;
}

.shameless-plug {
  font-size: 0.8em;
  text-align: center;
  display: block;
}

a {
  color: #0278a4;
}

.dark a {
  color: #00b9fd;
}

#frontcanvas, #backcanvas {
    touch-action: none;
}

 
  </style>
  <script type="text/javascript" >
///////////////////////////////////////////////
/*
  Split.js - v1.3.5
  MIT License
  https://github.com/nathancahill/Split.js
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Split=t()}(this,function(){"use strict";var e=window,t=e.document,n="addEventListener",i="removeEventListener",r="getBoundingClientRect",s=function(){return!1},o=e.attachEvent&&!e[n],a=["","-webkit-","-moz-","-o-"].filter(function(e){var n=t.createElement("div");return n.style.cssText="width:"+e+"calc(9px)",!!n.style.length}).shift()+"calc",l=function(e){return"string"==typeof e||e instanceof String?t.querySelector(e):e};return function(u,c){function z(e,t,n){var i=A(y,t,n);Object.keys(i).forEach(function(t){return e.style[t]=i[t]})}function h(e,t){var n=B(y,t);Object.keys(n).forEach(function(t){return e.style[t]=n[t]})}function f(e){var t=E[this.a],n=E[this.b],i=t.size+n.size;t.size=e/this.size*i,n.size=i-e/this.size*i,z(t.element,t.size,this.aGutterSize),z(n.element,n.size,this.bGutterSize)}function m(e){var t;this.dragging&&((t="touches"in e?e.touches[0][b]-this.start:e[b]-this.start)<=E[this.a].minSize+M+this.aGutterSize?t=E[this.a].minSize+this.aGutterSize:t>=this.size-(E[this.b].minSize+M+this.bGutterSize)&&(t=this.size-(E[this.b].minSize+this.bGutterSize)),f.call(this,t),c.onDrag&&c.onDrag())}function g(){var e=E[this.a].element,t=E[this.b].element;this.size=e[r]()[y]+t[r]()[y]+this.aGutterSize+this.bGutterSize,this.start=e[r]()[G]}function d(){var t=this,n=E[t.a].element,r=E[t.b].element;t.dragging&&c.onDragEnd&&c.onDragEnd(),t.dragging=!1,e[i]("mouseup",t.stop),e[i]("touchend",t.stop),e[i]("touchcancel",t.stop),t.parent[i]("mousemove",t.move),t.parent[i]("touchmove",t.move),delete t.stop,delete t.move,n[i]("selectstart",s),n[i]("dragstart",s),r[i]("selectstart",s),r[i]("dragstart",s),n.style.userSelect="",n.style.webkitUserSelect="",n.style.MozUserSelect="",n.style.pointerEvents="",r.style.userSelect="",r.style.webkitUserSelect="",r.style.MozUserSelect="",r.style.pointerEvents="",t.gutter.style.cursor="",t.parent.style.cursor=""}function S(t){var i=this,r=E[i.a].element,o=E[i.b].element;!i.dragging&&c.onDragStart&&c.onDragStart(),t.preventDefault(),i.dragging=!0,i.move=m.bind(i),i.stop=d.bind(i),e[n]("mouseup",i.stop),e[n]("touchend",i.stop),e[n]("touchcancel",i.stop),i.parent[n]("mousemove",i.move),i.parent[n]("touchmove",i.move),r[n]("selectstart",s),r[n]("dragstart",s),o[n]("selectstart",s),o[n]("dragstart",s),r.style.userSelect="none",r.style.webkitUserSelect="none",r.style.MozUserSelect="none",r.style.pointerEvents="none",o.style.userSelect="none",o.style.webkitUserSelect="none",o.style.MozUserSelect="none",o.style.pointerEvents="none",i.gutter.style.cursor=j,i.parent.style.cursor=j,g.call(i)}function v(e){e.forEach(function(t,n){if(n>0){var i=F[n-1],r=E[i.a],s=E[i.b];r.size=e[n-1],s.size=t,z(r.element,r.size,i.aGutterSize),z(s.element,s.size,i.bGutterSize)}})}function p(){F.forEach(function(e){e.parent.removeChild(e.gutter),E[e.a].element.style[y]="",E[e.b].element.style[y]=""})}void 0===c&&(c={});var y,b,G,E,w=l(u[0]).parentNode,D=e.getComputedStyle(w).flexDirection,U=c.sizes||u.map(function(){return 100/u.length}),k=void 0!==c.minSize?c.minSize:100,x=Array.isArray(k)?k:u.map(function(){return k}),L=void 0!==c.gutterSize?c.gutterSize:10,M=void 0!==c.snapOffset?c.snapOffset:30,O=c.direction||"horizontal",j=c.cursor||("horizontal"===O?"ew-resize":"ns-resize"),C=c.gutter||function(e,n){var i=t.createElement("div");return i.className="gutter gutter-"+n,i},A=c.elementStyle||function(e,t,n){var i={};return"string"==typeof t||t instanceof String?i[e]=t:i[e]=o?t+"%":a+"("+t+"% - "+n+"px)",i},B=c.gutterStyle||function(e,t){return n={},n[e]=t+"px",n;var n};"horizontal"===O?(y="width","clientWidth",b="clientX",G="left","paddingLeft"):"vertical"===O&&(y="height","clientHeight",b="clientY",G="top","paddingTop");var F=[];return E=u.map(function(e,t){var i,s={element:l(e),size:U[t],minSize:x[t]};if(t>0&&(i={a:t-1,b:t,dragging:!1,isFirst:1===t,isLast:t===u.length-1,direction:O,parent:w},i.aGutterSize=L,i.bGutterSize=L,i.isFirst&&(i.aGutterSize=L/2),i.isLast&&(i.bGutterSize=L/2),"row-reverse"===D||"column-reverse"===D)){var a=i.a;i.a=i.b,i.b=a}if(!o&&t>0){var c=C(t,O);h(c,L),c[n]("mousedown",S.bind(i)),c[n]("touchstart",S.bind(i)),w.insertBefore(c,s.element),i.gutter=c}0===t||t===u.length-1?z(s.element,s.size,L/2):z(s.element,s.size,L);var f=s.element[r]()[y];return f<s.minSize&&(s.minSize=f),t>0&&F.push(i),s}),o?{setSizes:v,destroy:p}:{setSizes:v,getSizes:function(){return E.map(function(e){return e.size})},collapse:function(e){if(e===F.length){var t=F[e-1];g.call(t),o||f.call(t,t.size-t.bGutterSize)}else{var n=F[e];g.call(n),o||f.call(n,n.aGutterSize)}},destroy:p}}});

///////////////////////////////////////////////

///////////////////////////////////////////////
// Copyright (c) 2013 Pieroxy <pieroxy@pieroxy.net>
// This work is free. You can redistribute it and/or modify it
// under the terms of the WTFPL, Version 2
// For more information see LICENSE.txt or http://www.wtfpl.net/
//
// For more information, the home page:
// http://pieroxy.net/blog/pages/lz-string/testing.html
//
// LZ-based compression algorithm, version 1.4.4
var LZString=function(){var o=String.fromCharCode,i={};var n={decompressFromBase64:function(o){return null==o?"":""==o?null:n._decompress(o.length,32,function(n){return function(o,n){if(!i[o]){i[o]={};for(var t=0;t<o.length;t++)i[o][o.charAt(t)]=t}return i[o][n]}("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",o.charAt(n))})},_decompress:function(i,n,t){var r,e,a,s,p,u,l,f=[],c=4,d=4,h=3,v="",g=[],m={val:t(0),position:n,index:1};for(r=0;r<3;r+=1)f[r]=r;for(a=0,p=Math.pow(2,2),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;switch(a){case 0:for(a=0,p=Math.pow(2,8),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;l=o(a);break;case 1:for(a=0,p=Math.pow(2,16),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;l=o(a);break;case 2:return""}for(f[3]=l,e=l,g.push(l);;){if(m.index>i)return"";for(a=0,p=Math.pow(2,h),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;switch(l=a){case 0:for(a=0,p=Math.pow(2,8),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;f[d++]=o(a),l=d-1,c--;break;case 1:for(a=0,p=Math.pow(2,16),u=1;u!=p;)s=m.val&m.position,m.position>>=1,0==m.position&&(m.position=n,m.val=t(m.index++)),a|=(s>0?1:0)*u,u<<=1;f[d++]=o(a),l=d-1,c--;break;case 2:return g.join("")}if(0==c&&(c=Math.pow(2,h),h++),f[l])v=f[l];else{if(l!==d)return null;v=e+e.charAt(0)}g.push(v),f[d++]=e+v.charAt(0),e=v,0==--c&&(c=Math.pow(2,h),h++)}}};return n}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module?module.exports=LZString:"undefined"!=typeof angular&&null!=angular&&angular.module("LZString",[]).factory("LZString",function(){return LZString});
///////////////////////////////////////////////

///////////////////////////////////////////////
/*!
 * PEP v0.4.3 | https://github.com/jquery/PEP
 * Copyright jQuery Foundation and other contributors | http://jquery.org/license
 */
! function (a, b) {
  "object" == typeof exports && "undefined" != typeof module ? module.exports = b() : "function" == typeof define && define.amd ? define(b) : a.PointerEventsPolyfill = b()
}(this, function () {
  "use strict";

  function a(a, b) {
    b = b || Object.create(null);
    var c = document.createEvent("Event");
    c.initEvent(a, b.bubbles || !1, b.cancelable || !1);
    for (var d, e = 2; e < m.length; e++) d = m[e], c[d] = b[d] || n[e];
    c.buttons = b.buttons || 0;
    var f = 0;
    return f = b.pressure && c.buttons ? b.pressure : c.buttons ? .5 : 0, c.x = c.clientX, c.y = c.clientY, c.pointerId = b.pointerId || 0, c.width = b.width || 0, c.height = b.height || 0, c.pressure = f, c.tiltX = b.tiltX || 0, c.tiltY = b.tiltY || 0, c.twist = b.twist || 0, c.tangentialPressure = b.tangentialPressure || 0, c.pointerType = b.pointerType || "", c.hwTimestamp = b.hwTimestamp || 0, c.isPrimary = b.isPrimary || !1, c
  }

  function b() {
    this.array = [], this.size = 0
  }

  function c(a, b, c, d) {
    this.addCallback = a.bind(d), this.removeCallback = b.bind(d), this.changedCallback = c.bind(d), A && (this.observer = new A(this.mutationWatcher.bind(this)))
  }

  function d(a) {
    return "body /shadow-deep/ " + e(a)
  }

  function e(a) {
    return '[touch-action="' + a + '"]'
  }

  function f(a) {
    return "{ -ms-touch-action: " + a + "; touch-action: " + a + "; }"
  }

  function g() {
    if (F) {
      D.forEach(function (a) {
        String(a) === a ? (E += e(a) + f(a) + "\n", G && (E += d(a) + f(a) + "\n")) : (E += a.selectors.map(e) + f(a.rule) + "\n", G && (E += a.selectors.map(d) + f(a.rule) + "\n"))
      });
      var a = document.createElement("style");
      a.textContent = E, document.head.appendChild(a)
    }
  }

  function h() {
    if (!window.PointerEvent) {
      if (window.PointerEvent = a, window.navigator.msPointerEnabled) {
        var b = window.navigator.msMaxTouchPoints;
        Object.defineProperty(window.navigator, "maxTouchPoints", {
          value: b,
          enumerable: !0
        }), u.registerSource("ms", _)
      } else Object.defineProperty(window.navigator, "maxTouchPoints", {
        value: 0,
        enumerable: !0
      }), u.registerSource("mouse", N), void 0 !== window.ontouchstart && u.registerSource("touch", V);
      u.register(document)
    }
  }

  function i(a) {
    if (!u.pointermap.has(a)) {
      var b = new Error("InvalidPointerId");
      throw b.name = "InvalidPointerId", b
    }
  }

  function j(a) {
    for (var b = a.parentNode; b && b !== a.ownerDocument;) b = b.parentNode;
    if (!b) {
      var c = new Error("InvalidStateError");
      throw c.name = "InvalidStateError", c
    }
  }

  function k(a) {
    var b = u.pointermap.get(a);
    return 0 !== b.buttons
  }

  function l() {
    window.Element && !Element.prototype.setPointerCapture && Object.defineProperties(Element.prototype, {
      setPointerCapture: {
        value: W
      },
      releasePointerCapture: {
        value: X
      },
      hasPointerCapture: {
        value: Y
      }
    })
  }
  var m = ["bubbles", "cancelable", "view", "detail", "screenX", "screenY", "clientX", "clientY", "ctrlKey", "altKey", "shiftKey", "metaKey", "button", "relatedTarget", "pageX", "pageY"],
    n = [!1, !1, null, null, 0, 0, 0, 0, !1, !1, !1, !1, 0, null, 0, 0],
    o = window.Map && window.Map.prototype.forEach,
    p = o ? Map : b;
  b.prototype = {
    set: function (a, b) {
      return void 0 === b ? this["delete"](a) : (this.has(a) || this.size++, void(this.array[a] = b))
    },
    has: function (a) {
      return void 0 !== this.array[a]
    },
    "delete": function (a) {
      this.has(a) && (delete this.array[a], this.size--)
    },
    get: function (a) {
      return this.array[a]
    },
    clear: function () {
      this.array.length = 0, this.size = 0
    },
    forEach: function (a, b) {
      return this.array.forEach(function (c, d) {
        a.call(b, c, d, this)
      }, this)
    }
  };
  var q = ["bubbles", "cancelable", "view", "detail", "screenX", "screenY", "clientX", "clientY", "ctrlKey", "altKey", "shiftKey", "metaKey", "button", "relatedTarget", "buttons", "pointerId", "width", "height", "pressure", "tiltX", "tiltY", "pointerType", "hwTimestamp", "isPrimary", "type", "target", "currentTarget", "which", "pageX", "pageY", "timeStamp"],
    r = [!1, !1, null, null, 0, 0, 0, 0, !1, !1, !1, !1, 0, null, 0, 0, 0, 0, 0, 0, 0, "", 0, !1, "", null, null, 0, 0, 0, 0],
    s = {
      pointerover: 1,
      pointerout: 1,
      pointerenter: 1,
      pointerleave: 1
    },
    t = "undefined" != typeof SVGElementInstance,
    u = {
      pointermap: new p,
      eventMap: Object.create(null),
      captureInfo: Object.create(null),
      eventSources: Object.create(null),
      eventSourceList: [],
      registerSource: function (a, b) {
        var c = b,
          d = c.events;
        d && (d.forEach(function (a) {
          c[a] && (this.eventMap[a] = c[a].bind(c))
        }, this), this.eventSources[a] = c, this.eventSourceList.push(c))
      },
      register: function (a) {
        for (var b, c = this.eventSourceList.length, d = 0; d < c && (b = this.eventSourceList[d]); d++)
          b.register.call(b, a)
      },
      unregister: function (a) {
        for (var b, c = this.eventSourceList.length, d = 0; d < c && (b = this.eventSourceList[d]); d++)
          b.unregister.call(b, a)
      },
      contains: function (a, b) {
        try {
          return a.contains(b)
        } catch (c) {
          return !1
        }
      },
      down: function (a) {
        a.bubbles = !0, this.fireEvent("pointerdown", a)
      },
      move: function (a) {
        a.bubbles = !0, this.fireEvent("pointermove", a)
      },
      up: function (a) {
        a.bubbles = !0, this.fireEvent("pointerup", a)
      },
      enter: function (a) {
        a.bubbles = !1, this.fireEvent("pointerenter", a)
      },
      leave: function (a) {
        a.bubbles = !1, this.fireEvent("pointerleave", a)
      },
      over: function (a) {
        a.bubbles = !0, this.fireEvent("pointerover", a)
      },
      out: function (a) {
        a.bubbles = !0, this.fireEvent("pointerout", a)
      },
      cancel: function (a) {
        a.bubbles = !0, this.fireEvent("pointercancel", a)
      },
      leaveOut: function (a) {
        this.out(a), this.propagate(a, this.leave, !1)
      },
      enterOver: function (a) {
        this.over(a), this.propagate(a, this.enter, !0)
      },
      eventHandler: function (a) {
        if (!a._handledByPE) {
          var b = a.type,
            c = this.eventMap && this.eventMap[b];
          c && c(a), a._handledByPE = !0
        }
      },
      listen: function (a, b) {
        b.forEach(function (b) {
          this.addEvent(a, b)
        }, this)
      },
      unlisten: function (a, b) {
        b.forEach(function (b) {
          this.removeEvent(a, b)
        }, this)
      },
      addEvent: function (a, b) {
        a.addEventListener(b, this.boundHandler)
      },
      removeEvent: function (a, b) {
        a.removeEventListener(b, this.boundHandler)
      },
      makeEvent: function (b, c) {
        this.captureInfo[c.pointerId] && (c.relatedTarget = null);
        var d = new a(b, c);
        return c.preventDefault && (d.preventDefault = c.preventDefault), d._target = d._target || c.target, d
      },
      fireEvent: function (a, b) {
        var c = this.makeEvent(a, b);
        return this.dispatchEvent(c)
      },
      cloneEvent: function (a) {
        for (var b, c = Object.create(null), d = 0; d < q.length; d++) b = q[d], c[b] = a[b] || r[d], !t || "target" !== b && "relatedTarget" !== b || c[b] instanceof SVGElementInstance && (c[b] = c[b].correspondingUseElement);
        return a.preventDefault && (c.preventDefault = function () {
          a.preventDefault()
        }), c
      },
      getTarget: function (a) {
        var b = this.captureInfo[a.pointerId];
        return b ? a._target !== b && a.type in s ? void 0 : b : a._target
      },
      propagate: function (a, b, c) {
        for (var d = a.target, e = []; d !== document && !d.contains(a.relatedTarget);)
          if (e.push(d), d = d.parentNode, !d) return;
        c && e.reverse(), e.forEach(function (c) {
          a.target = c, b.call(this, a)
        }, this)
      },
      setCapture: function (b, c, d) {
        this.captureInfo[b] && this.releaseCapture(b, d), this.captureInfo[b] = c, this.implicitRelease = this.releaseCapture.bind(this, b, d), document.addEventListener("pointerup", this.implicitRelease), document.addEventListener("pointercancel", this.implicitRelease);
        var e = new a("gotpointercapture");
        e.pointerId = b, e._target = c, d || this.asyncDispatchEvent(e)
      },
      releaseCapture: function (b, c) {
        var d = this.captureInfo[b];
        if (d) {
          this.captureInfo[b] = void 0, document.removeEventListener("pointerup", this.implicitRelease), document.removeEventListener("pointercancel", this.implicitRelease);
          var e = new a("lostpointercapture");
          e.pointerId = b, e._target = d, c || this.asyncDispatchEvent(e)
        }
      },
      dispatchEvent: /*scope.external.dispatchEvent || */ function (a) {
        var b = this.getTarget(a);
        if (b) return b.dispatchEvent(a)
      },
      asyncDispatchEvent: function (a) {
        requestAnimationFrame(this.dispatchEvent.bind(this, a))
      }
    };
  u.boundHandler = u.eventHandler.bind(u);
  var v = {
      shadow: function (a) {
        if (a) return a.shadowRoot || a.webkitShadowRoot
      },
      canTarget: function (a) {
        return a && Boolean(a.elementFromPoint)
      },
      targetingShadow: function (a) {
        var b = this.shadow(a);
        if (this.canTarget(b)) return b
      },
      olderShadow: function (a) {
        var b = a.olderShadowRoot;
        if (!b) {
          var c = a.querySelector("shadow");
          c && (b = c.olderShadowRoot)
        }
        return b
      },
      allShadows: function (a) {
        for (var b = [], c = this.shadow(a); c;) b.push(c), c = this.olderShadow(c);
        return b
      },
      searchRoot: function (a, b, c) {
        if (a) {
          var d, e, f = a.elementFromPoint(b, c);
          for (e = this.targetingShadow(f); e;) {
            if (d = e.elementFromPoint(b, c)) {
              var g = this.targetingShadow(d);
              return this.searchRoot(g, b, c) || d
            }
            e = this.olderShadow(e)
          }
          return f
        }
      },
      owner: function (a) {
        for (var b = a; b.parentNode;) b = b.parentNode;
        return b.nodeType !== Node.DOCUMENT_NODE && b.nodeType !== Node.DOCUMENT_FRAGMENT_NODE && (b = document), b
      },
      findTarget: function (a) {
        var b = a.clientX,
          c = a.clientY,
          d = this.owner(a.target);
        return d.elementFromPoint(b, c) || (d = document), this.searchRoot(d, b, c)
      }
    },
    w = Array.prototype.forEach.call.bind(Array.prototype.forEach),
    x = Array.prototype.map.call.bind(Array.prototype.map),
    y = Array.prototype.slice.call.bind(Array.prototype.slice),
    z = Array.prototype.filter.call.bind(Array.prototype.filter),
    A = window.MutationObserver || window.WebKitMutationObserver,
    B = "[touch-action]",
    C = {
      subtree: !0,
      childList: !0,
      attributes: !0,
      attributeOldValue: !0,
      attributeFilter: ["touch-action"]
    };
  c.prototype = {
    watchSubtree: function (a) {
      //
      this.observer && v.canTarget(a) && this.observer.observe(a, C)
    },
    enableOnSubtree: function (a) {
      this.watchSubtree(a), a === document && "complete" !== document.readyState ? this.installOnLoad() : this.installNewSubtree(a)
    },
    installNewSubtree: function (a) {
      w(this.findElements(a), this.addElement, this)
    },
    findElements: function (a) {
      return a.querySelectorAll ? a.querySelectorAll(B) : []
    },
    removeElement: function (a) {
      this.removeCallback(a)
    },
    addElement: function (a) {
      this.addCallback(a)
    },
    elementChanged: function (a, b) {
      this.changedCallback(a, b)
    },
    concatLists: function (a, b) {
      return a.concat(y(b))
    },
    installOnLoad: function () {
      document.addEventListener("readystatechange", function () {
        "complete" === document.readyState && this.installNewSubtree(document)
      }.bind(this))
    },
    isElement: function (a) {
      return a.nodeType === Node.ELEMENT_NODE
    },
    flattenMutationTree: function (a) {
      var b = x(a, this.findElements, this);
      return b.push(z(a, this.isElement)), b.reduce(this.concatLists, [])
    },
    mutationWatcher: function (a) {
      a.forEach(this.mutationHandler, this)
    },
    mutationHandler: function (a) {
      if ("childList" === a.type) {
        var b = this.flattenMutationTree(a.addedNodes);
        b.forEach(this.addElement, this);
        var c = this.flattenMutationTree(a.removedNodes);
        c.forEach(this.removeElement, this)
      } else "attributes" === a.type && this.elementChanged(a.target, a.oldValue)
    }
  };
  var D = ["none", "auto", "pan-x", "pan-y", {
      rule: "pan-x pan-y",
      selectors: ["pan-x pan-y", "pan-y pan-x"]
    }],
    E = "",
    F = window.PointerEvent || window.MSPointerEvent,
    G = !window.ShadowDOMPolyfill && document.head.createShadowRoot,
    H = u.pointermap,
    I = 25,
    J = [1, 4, 2, 8, 16],
    K = !1;
  try {
    K = 1 === new MouseEvent("test", {
      buttons: 1
    }).buttons
  } catch (L) {}
  var M, N = {
      POINTER_ID: 1,
      POINTER_TYPE: "mouse",
      events: ["mousedown", "mousemove", "mouseup", "mouseover", "mouseout"],
      register: function (a) {
        u.listen(a, this.events)
      },
      unregister: function (a) {
        u.unlisten(a, this.events)
      },
      lastTouches: [],
      isEventSimulatedFromTouch: function (a) {
        for (var b, c = this.lastTouches, d = a.clientX, e = a.clientY, f = 0, g = c.length; f < g && (b = c[f]); f++) {
          var h = Math.abs(d - b.x),
            i = Math.abs(e - b.y);
          if (h <= I && i <= I) return !0
        }
      },
      prepareEvent: function (a) {
        var b = u.cloneEvent(a),
          c = b.preventDefault;
        return b.preventDefault = function () {
          a.preventDefault(), c()
        }, b.pointerId = this.POINTER_ID, b.isPrimary = !0, b.pointerType = this.POINTER_TYPE, b
      },
      prepareButtonsForMove: function (a, b) {
        var c = H.get(this.POINTER_ID);
        0 !== b.which && c ? a.buttons = c.buttons : a.buttons = 0, b.buttons = a.buttons
      },
      mousedown: function (a) {
        if (!this.isEventSimulatedFromTouch(a)) {
          var b = H.get(this.POINTER_ID),
            c = this.prepareEvent(a);
          K || (c.buttons = J[c.button], b && (c.buttons |= b.buttons), a.buttons = c.buttons), H.set(this.POINTER_ID, a), b && 0 !== b.buttons ? u.move(c) : u.down(c)
        }
      },
      mousemove: function (a) {
        if (!this.isEventSimulatedFromTouch(a)) {
          var b = this.prepareEvent(a);
          K || this.prepareButtonsForMove(b, a), b.button = -1, H.set(this.POINTER_ID, a), u.move(b)
        }
      },
      mouseup: function (a) {
        if (!this.isEventSimulatedFromTouch(a)) {
          var b = H.get(this.POINTER_ID),
            c = this.prepareEvent(a);
          if (!K) {
            var d = J[c.button];
            c.buttons = b ? b.buttons & ~d : 0, a.buttons = c.buttons
          }
          H.set(this.POINTER_ID, a),
            c.buttons &= ~J[c.button], 0 === c.buttons ? u.up(c) : u.move(c)
        }
      },
      mouseover: function (a) {
        if (!this.isEventSimulatedFromTouch(a)) {
          var b = this.prepareEvent(a);
          K || this.prepareButtonsForMove(b, a), b.button = -1, H.set(this.POINTER_ID, a), u.enterOver(b)
        }
      },
      mouseout: function (a) {
        if (!this.isEventSimulatedFromTouch(a)) {
          var b = this.prepareEvent(a);
          K || this.prepareButtonsForMove(b, a), b.button = -1, u.leaveOut(b)
        }
      },
      cancel: function (a) {
        var b = this.prepareEvent(a);
        u.cancel(b), this.deactivateMouse()
      },
      deactivateMouse: function () {
        H["delete"](this.POINTER_ID)
      }
    },
    O = u.captureInfo,
    P = v.findTarget.bind(v),
    Q = v.allShadows.bind(v),
    R = u.pointermap,
    S = 2500,
    T = 200,
    U = "touch-action",
    V = {
      events: ["touchstart", "touchmove", "touchend", "touchcancel"],
      register: function (a) {
        M.enableOnSubtree(a)
      },
      unregister: function () {},
      elementAdded: function (a) {
        var b = a.getAttribute(U),
          c = this.touchActionToScrollType(b);
        c && (a._scrollType = c, u.listen(a, this.events),
          Q(a).forEach(function (a) {
            a._scrollType = c, u.listen(a, this.events)
          }, this))
      },
      elementRemoved: function (a) {
        a._scrollType = void 0, u.unlisten(a, this.events),
          Q(a).forEach(function (a) {
            a._scrollType = void 0, u.unlisten(a, this.events)
          }, this)
      },
      elementChanged: function (a, b) {
        var c = a.getAttribute(U),
          d = this.touchActionToScrollType(c),
          e = this.touchActionToScrollType(b);
        d && e ? (a._scrollType = d, Q(a).forEach(function (a) {
          a._scrollType = d
        }, this)) : e ? this.elementRemoved(a) : d && this.elementAdded(a)
      },
      scrollTypes: {
        EMITTER: "none",
        XSCROLLER: "pan-x",
        YSCROLLER: "pan-y",
        SCROLLER: /^(?:pan-x pan-y)|(?:pan-y pan-x)|auto$/
      },
      touchActionToScrollType: function (a) {
        var b = a,
          c = this.scrollTypes;
        return "none" === b ? "none" : b === c.XSCROLLER ? "X" : b === c.YSCROLLER ? "Y" : c.SCROLLER.exec(b) ? "XY" : void 0
      },
      POINTER_TYPE: "touch",
      firstTouch: null,
      isPrimaryTouch: function (a) {
        return this.firstTouch === a.identifier
      },
      setPrimaryTouch: function (a) {
        (0 === R.size || 1 === R.size && R.has(1)) && (this.firstTouch = a.identifier, this.firstXY = {
          X: a.clientX,
          Y: a.clientY
        }, this.scrolling = !1, this.cancelResetClickCount())
      },
      removePrimaryPointer: function (a) {
        a.isPrimary && (this.firstTouch = null, this.firstXY = null, this.resetClickCount())
      },
      clickCount: 0,
      resetId: null,
      resetClickCount: function () {
        var a = function () {
          this.clickCount = 0, this.resetId = null
        }.bind(this);
        this.resetId = setTimeout(a, T)
      },
      cancelResetClickCount: function () {
        this.resetId && clearTimeout(this.resetId)
      },
      typeToButtons: function (a) {
        var b = 0;
        return "touchstart" !== a && "touchmove" !== a || (b = 1), b
      },
      touchToPointer: function (a) {
        var b = this.currentTouchEvent,
          c = u.cloneEvent(a),
          d = c.pointerId = a.identifier + 2;
        c.target = O[d] || P(c), c.bubbles = !0, c.cancelable = !0, c.detail = this.clickCount, c.button = 0, c.buttons = this.typeToButtons(b.type), c.width = 2 * (a.radiusX || a.webkitRadiusX || 0), c.height = 2 * (a.radiusY || a.webkitRadiusY || 0), c.pressure = a.force || a.webkitForce || .5, c.isPrimary = this.isPrimaryTouch(a), c.pointerType = this.POINTER_TYPE,
          c.altKey = b.altKey, c.ctrlKey = b.ctrlKey, c.metaKey = b.metaKey, c.shiftKey = b.shiftKey;
        var e = this;
        return c.preventDefault = function () {
          e.scrolling = !1, e.firstXY = null, b.preventDefault()
        }, c
      },
      processTouches: function (a, b) {
        var c = a.changedTouches;
        this.currentTouchEvent = a;
        for (var d, e = 0; e < c.length; e++) d = c[e], b.call(this, this.touchToPointer(d))
      },
      shouldScroll: function (a) {
        if (this.firstXY) {
          var b, c = a.currentTarget._scrollType;
          if ("none" === c)
            b = !1;
          else if ("XY" === c)
            b = !0;
          else {
            var d = a.changedTouches[0],
              e = c,
              f = "Y" === c ? "X" : "Y",
              g = Math.abs(d["client" + e] - this.firstXY[e]),
              h = Math.abs(d["client" + f] - this.firstXY[f]);
            b = g >= h
          }
          return this.firstXY = null, b
        }
      },
      findTouch: function (a, b) {
        for (var c, d = 0, e = a.length; d < e && (c = a[d]); d++)
          if (c.identifier === b) return !0
      },
      vacuumTouches: function (a) {
        var b = a.touches;
        if (R.size >= b.length) {
          var c = [];
          R.forEach(function (a, d) {
            if (1 !== d && !this.findTouch(b, d - 2)) {
              var e = a.out;
              c.push(e)
            }
          }, this), c.forEach(this.cancelOut, this)
        }
      },
      touchstart: function (a) {
        this.vacuumTouches(a), this.setPrimaryTouch(a.changedTouches[0]), this.dedupSynthMouse(a), this.scrolling || (this.clickCount++, this.processTouches(a, this.overDown))
      },
      overDown: function (a) {
        R.set(a.pointerId, {
          target: a.target,
          out: a,
          outTarget: a.target
        }), u.enterOver(a), u.down(a)
      },
      touchmove: function (a) {
        this.scrolling || (this.shouldScroll(a) ? (this.scrolling = !0, this.touchcancel(a)) : (a.preventDefault(), this.processTouches(a, this.moveOverOut)))
      },
      moveOverOut: function (a) {
        var b = a,
          c = R.get(b.pointerId);
        if (c) {
          var d = c.out,
            e = c.outTarget;
          u.move(b), d && e !== b.target && (d.relatedTarget = b.target, b.relatedTarget = e,
            d.target = e, b.target ? (u.leaveOut(d), u.enterOver(b)) : (
              b.target = e, b.relatedTarget = null, this.cancelOut(b))), c.out = b, c.outTarget = b.target
        }
      },
      touchend: function (a) {
        this.dedupSynthMouse(a), this.processTouches(a, this.upOut)
      },
      upOut: function (a) {
        this.scrolling || (u.up(a), u.leaveOut(a)), this.cleanUpPointer(a)
      },
      touchcancel: function (a) {
        this.processTouches(a, this.cancelOut)
      },
      cancelOut: function (a) {
        u.cancel(a), u.leaveOut(a), this.cleanUpPointer(a)
      },
      cleanUpPointer: function (a) {
        R["delete"](a.pointerId), this.removePrimaryPointer(a)
      },
      dedupSynthMouse: function (a) {
        var b = N.lastTouches,
          c = a.changedTouches[0];
        if (this.isPrimaryTouch(c)) {
          var d = {
            x: c.clientX,
            y: c.clientY
          };
          b.push(d);
          var e = function (a, b) {
            var c = a.indexOf(b);
            c > -1 && a.splice(c, 1)
          }.bind(null, b, d);
          setTimeout(e, S)
        }
      }
    };
  M = new c(V.elementAdded, V.elementRemoved, V.elementChanged, V);
  var W, X, Y, Z = u.pointermap,
    $ = window.MSPointerEvent && "number" == typeof window.MSPointerEvent.MSPOINTER_TYPE_MOUSE,
    _ = {
      events: ["MSPointerDown", "MSPointerMove", "MSPointerUp", "MSPointerOut", "MSPointerOver", "MSPointerCancel", "MSGotPointerCapture", "MSLostPointerCapture"],
      register: function (a) {
        u.listen(a, this.events)
      },
      unregister: function (a) {
        u.unlisten(a, this.events)
      },
      POINTER_TYPES: ["", "unavailable", "touch", "pen", "mouse"],
      prepareEvent: function (a) {
        var b = a;
        return $ && (b = u.cloneEvent(a), b.pointerType = this.POINTER_TYPES[a.pointerType]), b
      },
      cleanup: function (a) {
        Z["delete"](a)
      },
      MSPointerDown: function (a) {
        Z.set(a.pointerId, a);
        var b = this.prepareEvent(a);
        u.down(b)
      },
      MSPointerMove: function (a) {
        var b = this.prepareEvent(a);
        u.move(b)
      },
      MSPointerUp: function (a) {
        var b = this.prepareEvent(a);
        u.up(b), this.cleanup(a.pointerId)
      },
      MSPointerOut: function (a) {
        var b = this.prepareEvent(a);
        u.leaveOut(b)
      },
      MSPointerOver: function (a) {
        var b = this.prepareEvent(a);
        u.enterOver(b)
      },
      MSPointerCancel: function (a) {
        var b = this.prepareEvent(a);
        u.cancel(b), this.cleanup(a.pointerId)
      },
      MSLostPointerCapture: function (a) {
        var b = u.makeEvent("lostpointercapture", a);
        u.dispatchEvent(b)
      },
      MSGotPointerCapture: function (a) {
        var b = u.makeEvent("gotpointercapture", a);
        u.dispatchEvent(b)
      }
    },
    aa = window.navigator;
  aa.msPointerEnabled ? (W = function (a) {
    i(a), j(this), k(a) && (u.setCapture(a, this, !0), this.msSetPointerCapture(a))
  }, X = function (a) {
    i(a), u.releaseCapture(a, !0), this.msReleasePointerCapture(a)
  }) : (W = function (a) {
    i(a), j(this), k(a) && u.setCapture(a, this)
  }, X = function (a) {
    i(a), u.releaseCapture(a)
  }), Y = function (a) {
    return !!u.captureInfo[a]
  }, g(), h(), l();
  var ba = {
    dispatcher: u,
    Installer: c,
    PointerEvent: a,
    PointerMap: p,
    targetFinding: v
  };
  return ba
});
///////////////////////////////////////////////

///////////////////////////////////////////////
var config = {"show_fabrication":false,"redraw_on_drag":true,"highlight_pin1":false,"extra_fields":[],"dark_mode":false,"bom_view":"left-right","board_rotation":0,"checkboxes":"Sourced,Placed","show_silkscreen":true,"show_pads":true,"layer_view":"FB"};
///////////////////////////////////////////////

///////////////////////////////////////////////
var pcbdata = {"ibom_version":"v2.3-50-g53ae\n","edges_bbox":{"minx":3945,"miny":3346,"maxx":4095,"maxy":3496.6},"edges":[{"type":"polyline","net":"S$89168","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4045.5,3470.5 4045.4244,3490.0756 4044,3491.5 4020,3491.5"},{"type":"polyline","net":"S$44971","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3967.4979,3378.5001 4072.5,3378.5"},{"type":"polyline","net":"S$89168","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3994.5,3470.5 3994.5756,3490.0756 3996,3491.5 4020,3491.5"},{"type":"arc","width":1,"svgpath":"M3967.3563,3378.4071 A62.992,62.992 0 0 0 3994.5112,3470.6047","net":"S$89168"},{"type":"arc","width":1,"svgpath":"M4045.537,3470.5834 A62.992,62.992 0 0 0 4072.7224,3378.5277","net":"S$89168"}],"drawings":{"silkscreen":{"F":[{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4019.1008,3462.322 4019.1008,3458.5469 4013.8992,3458.5469 4013.8992,3462.322"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4019.1008,3465.678 4019.1008,3469.4531 4013.8992,3469.4531 4013.8992,3465.678"},{"type":"text","svgpath":"M 4000.96 3462.77 L 4001.16 3463.39 L 4001.78 3463.8 L 4002.8 3464 L 4003.41 3464 L 4004.44 3463.8 L 4005.05 3463.39 L 4005.25 3462.77 L 4005.25 3462.36 L 4005.05 3461.75 L 4004.44 3461.34 L 4003.41 3461.14 L 4002.8 3461.14 L 4001.78 3461.34 L 4001.16 3461.75 L 4000.96 3462.36 L 4000.96 3462.77 M 4004.23 3459.58 L 4004.44 3459.79 L 4004.64 3459.58 L 4004.44 3459.38 L 4004.23 3459.58 M 4000.96 3457 L 4001.16 3457.62 L 4001.57 3457.82 L 4001.98 3457.82 L 4002.39 3457.62 L 4002.6 3457.21 L 4002.8 3456.39 L 4003 3455.78 L 4003.41 3455.37 L 4003.82 3455.16 L 4004.44 3455.16 L 4004.85 3455.37 L 4005.05 3455.57 L 4005.25 3456.19 L 4005.25 3457 L 4005.05 3457.62 L 4004.85 3457.82 L 4004.44 3458.03 L 4003.82 3458.03 L 4003.41 3457.82 L 4003 3457.41 L 4002.8 3456.8 L 4002.6 3455.98 L 4002.39 3455.57 L 4001.98 3455.37 L 4001.57 3455.37 L 4001.16 3455.57 L 4000.96 3456.19 L 4000.96 3457 M 4000.96 3453.81 L 4005.25 3453.81 M 4000.96 3453.81 L 4000.96 3451.97 L 4001.16 3451.36 L 4001.37 3451.15 L 4001.78 3450.95 L 4002.19 3450.95 L 4002.6 3451.15 L 4002.8 3451.36 L 4003 3451.97 L 4003 3453.81 M 4003 3452.38 L 4005.25 3450.95","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4026.1008,3462.322 4026.1008,3458.5469 4020.8992,3458.5469 4020.8992,3462.322"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4026.1008,3465.678 4026.1008,3469.4531 4020.8992,3469.4531 4020.8992,3465.678"},{"type":"text","svgpath":"M 4007.96 3462.77 L 4008.16 3463.39 L 4008.78 3463.8 L 4009.8 3464 L 4010.41 3464 L 4011.44 3463.8 L 4012.05 3463.39 L 4012.25 3462.77 L 4012.25 3462.36 L 4012.05 3461.75 L 4011.44 3461.34 L 4010.41 3461.14 L 4009.8 3461.14 L 4008.78 3461.34 L 4008.16 3461.75 L 4007.96 3462.36 L 4007.96 3462.77 M 4011.23 3459.58 L 4011.44 3459.79 L 4011.64 3459.58 L 4011.44 3459.38 L 4011.23 3459.58 M 4007.96 3457 L 4008.16 3457.62 L 4008.57 3457.82 L 4008.98 3457.82 L 4009.39 3457.62 L 4009.6 3457.21 L 4009.8 3456.39 L 4010 3455.78 L 4010.41 3455.37 L 4010.82 3455.16 L 4011.44 3455.16 L 4011.85 3455.37 L 4012.05 3455.57 L 4012.25 3456.19 L 4012.25 3457 L 4012.05 3457.62 L 4011.85 3457.82 L 4011.44 3458.03 L 4010.82 3458.03 L 4010.41 3457.82 L 4010 3457.41 L 4009.8 3456.8 L 4009.6 3455.98 L 4009.39 3455.57 L 4008.98 3455.37 L 4008.57 3455.37 L 4008.16 3455.57 L 4007.96 3456.19 L 4007.96 3457 M 4007.96 3453.81 L 4012.25 3453.81 M 4007.96 3453.81 L 4007.96 3451.97 L 4008.16 3451.36 L 4008.37 3451.15 L 4008.78 3450.95 L 4009.19 3450.95 L 4009.6 3451.15 L 4009.8 3451.36 L 4010 3451.97 L 4010 3453.81 M 4010 3452.38 L 4012.25 3450.95","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3981.0174,3443.2433 3983.2446,3441.0161"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3983.2443,3447.1953 3981.0172,3444.9683"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3987.1964,3443.2431 3984.9694,3441.0161"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3984.8313,3448.8147 3987.0584,3451.0418"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3988.7835,3451.0418 3991.0105,3448.8148"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3988.7833,3444.8627 3991.0104,3447.0898"},{"type":"arc","width":1,"svgpath":"M 3988.7836 3451.042 A 1.2198 1.2198 0 0 1 3987.0585 3451.042","net":""},{"type":"arc","width":1,"svgpath":"M 3991.0107 3447.0898 A 1.2198 1.2198 0 0 1 3991.0106 3448.8149","net":""},{"type":"arc","width":1,"svgpath":"M 3981.0174 3444.9684 A 1.2198 1.2198 0 0 1 3981.0174 3443.2433","net":""},{"type":"arc","width":1,"svgpath":"M 3983.2445 3441.0162 A 1.2198 1.2198 0 0 1 3984.9695 3441.0162","net":""},{"type":"text","svgpath":"M 3976.2985 3457.1157 L 3975.8601 3456.9743 L 3974.9974 3456.9743 L 3978.0309 3453.9408 M 3973.1731 3455.15 L 3973.7458 3455.4399 L 3974.4742 3455.2914 L 3975.3439 3454.7186 L 3975.7752 3454.2873 L 3976.3551 3453.4105 L 3976.4965 3452.6892 L 3976.2066 3452.1165 L 3975.9167 3451.8266 L 3975.3439 3451.5366 L 3974.6227 3451.6781 L 3973.7458 3452.2579 L 3973.3145 3452.6892 L 3972.7417 3453.559 L 3972.5933 3454.2873 L 3972.8832 3454.86 L 3973.1731 3455.15 M 3970.1962 3452.173 L 3970.7689 3452.463 L 3971.4972 3452.3145 L 3972.3599 3451.7346 L 3972.7912 3451.3033 L 3973.3781 3450.4336 L 3973.5196 3449.7123 L 3973.2297 3449.1396 L 3972.9397 3448.8496 L 3972.3599 3448.5527 L 3971.6387 3448.6941 L 3970.7689 3449.281 L 3970.3376 3449.7123 L 3969.7578 3450.575 L 3969.6093 3451.3033 L 3969.9062 3451.8831 L 3970.1962 3452.173 M 3969.0931 3449.0476 L 3971.1154 3447.0253 M 3969.6729 3448.4678 L 3968.8102 3448.4678 L 3968.3718 3448.3264 L 3967.9334 3447.888 L 3967.792 3447.4496 L 3968.0819 3446.8768 L 3969.5244 3445.4343","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4055.7567,3441.0174 4057.9839,3443.2446"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4051.8047,3443.2443 4054.0317,3441.0172"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4055.7569,3447.1964 4057.9839,3444.9694"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4050.1853,3444.8313 4047.9582,3447.0584"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4047.9582,3448.7835 4050.1852,3451.0105"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4054.1373,3448.7833 4051.9102,3451.0104"},{"type":"arc","width":1,"svgpath":"M 4047.958 3448.7836 A 1.2198 1.2198 0 0 1 4047.958 3447.0585","net":""},{"type":"arc","width":1,"svgpath":"M 4051.9102 3451.0107 A 1.2198 1.2198 0 0 1 4050.1851 3451.0106","net":""},{"type":"arc","width":1,"svgpath":"M 4054.0316 3441.0174 A 1.2198 1.2198 0 0 1 4055.7567 3441.0174","net":""},{"type":"arc","width":1,"svgpath":"M 4057.9838 3443.2445 A 1.2198 1.2198 0 0 1 4057.9838 3444.9695","net":""},{"type":"text","svgpath":"M 4041.8843 3436.2985 L 4042.0257 3435.8601 L 4042.0257 3434.9974 L 4045.0592 3438.0309 M 4043.85 3433.1731 L 4043.5601 3433.7458 L 4043.7086 3434.4742 L 4044.2814 3435.3439 L 4044.7127 3435.7752 L 4045.5895 3436.3551 L 4046.3108 3436.4965 L 4046.8835 3436.2066 L 4047.1734 3435.9167 L 4047.4634 3435.3439 L 4047.3219 3434.6227 L 4046.7421 3433.7458 L 4046.3108 3433.3145 L 4045.441 3432.7417 L 4044.7127 3432.5933 L 4044.14 3432.8832 L 4043.85 3433.1731 M 4046.827 3430.1962 L 4046.537 3430.7689 L 4046.6855 3431.4972 L 4047.2654 3432.3599 L 4047.6967 3432.7912 L 4048.5664 3433.3781 L 4049.2877 3433.5196 L 4049.8604 3433.2297 L 4050.1504 3432.9397 L 4050.4473 3432.3599 L 4050.3059 3431.6387 L 4049.719 3430.7689 L 4049.2877 3430.3376 L 4048.425 3429.7578 L 4047.6967 3429.6093 L 4047.1169 3429.9062 L 4046.827 3430.1962 M 4049.9524 3429.0931 L 4051.9747 3431.1154 M 4050.5322 3429.6729 L 4050.5322 3428.8102 L 4050.6736 3428.3718 L 4051.112 3427.9334 L 4051.5504 3427.792 L 4052.1232 3428.0819 L 4053.5657 3429.5244","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.5984,"svgpath":"M3977.2163,3451.6081 3977.6338,3451.1906 3981.5312,3455.0879 3981.6703,3455.2271 3981.2528,3455.6447"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.5984,"svgpath":"M3977.2163,3451.6081 3981.2529,3455.6447"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3973.1795,3453.4176 3973.2124,3453.4506"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.5984,"svgpath":"M3979.7216,3447.1538 3974.1538,3452.7216"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.5984,"svgpath":"M3980.2784,3458.8462 3985.8462,3453.2784"},{"type":"text","svgpath":"M 3964.0623 3438.4762 L 3967.8312 3440.7884 M 3965.5119 3437.0266 L 3967.8312 3440.7884 M 3965.5119 3437.0266 L 3969.2737 3439.3459 M 3966.9544 3435.5841 L 3969.2737 3439.3459 M 3970.3768 3433.0385 L 3969.7969 3433.0385 L 3969.2101 3433.3284 L 3968.6373 3433.9012 L 3968.3474 3434.488 L 3968.3474 3435.0679 L 3968.6373 3435.3578 L 3969.0687 3435.4922 L 3969.3586 3435.4993 L 3969.7898 3435.3508 L 3970.9496 3434.7709 L 3971.3879 3434.6295 L 3971.6708 3434.6295 L 3972.1092 3434.7709 L 3972.5405 3435.2023 L 3972.5405 3435.7821 L 3972.2506 3436.369 L 3971.6779 3436.9418 L 3971.091 3437.2316 L 3970.5111 3437.2317 M 3971.7627 3432.2324 L 3971.6142 3432.0839 L 3971.4728 3431.6456 L 3971.4728 3431.3626 L 3971.6142 3430.9243 L 3972.194 3430.3445 L 3972.6325 3430.203 L 3972.9153 3430.2031 L 3973.3537 3430.3444 L 3973.6437 3430.6344 L 3973.7851 3431.0728 L 3973.9264 3431.794 L 3973.9335 3434.6861 L 3975.9559 3432.6638 M 3974.5911 3427.9474 L 3974.3083 3428.5271 L 3974.4568 3428.9585 L 3974.7467 3429.2484 L 3975.171 3429.3898 L 3975.6093 3429.2485 L 3976.3306 3428.81 L 3976.9105 3428.5271 L 3977.4903 3428.5272 L 3977.9216 3428.6757 L 3978.3529 3429.107 L 3978.5014 3429.5383 L 3978.5014 3429.8212 L 3978.2115 3430.4081 L 3977.6317 3430.9879 L 3977.0519 3431.2707 L 3976.7691 3431.2707 L 3976.3306 3431.1293 L 3975.8993 3430.698 L 3975.7579 3430.2596 L 3975.7508 3429.6868 L 3976.0407 3429.1 L 3976.4791 3428.3787 L 3976.6205 3427.9403 L 3976.4791 3427.516 L 3976.1892 3427.2261 L 3975.7578 3427.0776 L 3975.171 3427.3675 L 3974.5911 3427.9474 M 3977.4267 3426.2715 L 3977.5751 3425.8402 L 3977.5752 3424.9634 L 3980.6157 3428.0039 M 3979.3995 3424.5957 L 3979.251 3424.4472 L 3979.1096 3424.0088 L 3979.1096 3423.7259 L 3979.2509 3423.2875 L 3979.8308 3422.7077 L 3980.2692 3422.5662 L 3980.5521 3422.5663 L 3980.9904 3422.7077 L 3981.2803 3422.9976 L 3981.4218 3423.436 L 3981.5632 3424.1572 L 3981.5703 3427.0493 L 3983.5926 3425.027 M 3981.5067 3421.0319 L 3984.5472 3424.0724 M 3981.5067 3421.0319 L 3982.8078 3419.7308 L 3983.3946 3419.4408 L 3983.6775 3419.4409 L 3984.1088 3419.5893 L 3984.3987 3419.8793 L 3984.5472 3420.3106 L 3984.5472 3420.5935 L 3984.2573 3421.1803 M 3982.9562 3422.4814 L 3984.2573 3421.1803 L 3984.8371 3420.8833 L 3985.127 3420.8904 L 3985.5584 3421.0389 L 3985.9897 3421.4702 L 3986.1382 3421.9016 L 3986.1382 3422.1844 L 3985.8483 3422.7713 L 3984.5472 3424.0724 M 3986.223 3419.7944 L 3988.8323 3417.1852 M 3988.0474 3414.4911 L 3991.0879 3417.5317 M 3988.0474 3414.4911 L 3992.2405 3416.3791 M 3990.3596 3412.1789 L 3992.2405 3416.3791 M 3990.3596 3412.1789 L 3993.4002 3415.2194 M 3991.3142 3411.2243 L 3994.3547 3414.2649 M 3992.2688 3410.2697 L 3995.3094 3413.3102 M 3992.2688 3410.2697 L 3997.3317 3411.2879 M 3994.2911 3408.2474 L 3997.3317 3411.2879 M 3995.2457 3407.2928 L 3998.2862 3410.3333","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.5984,"svgpath":"M4061.3919,3450.2163 4061.8094,3450.6338 4057.9121,3454.5312 4057.7729,3454.6703 4057.3553,3454.2528"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.5984,"svgpath":"M4061.3919,3450.2163 4057.3553,3454.2529"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4059.5824,3446.1795 4059.5494,3446.2125"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.5984,"svgpath":"M4065.8461,3452.7216 4060.2784,3447.1539"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.5984,"svgpath":"M4054.1539,3453.2784 4059.7216,3458.8461"},{"type":"text","svgpath":"M 4074.519 3437.0632 L 4072.2068 3440.818 M 4075.9686 3438.5128 L 4072.2068 3440.818 M 4075.9686 3438.5128 L 4073.6564 3442.2675 M 4077.4111 3439.9553 L 4073.6564 3442.2675 M 4079.9567 3443.3635 L 4079.9637 3442.7908 L 4079.6668 3442.211 L 4079.0869 3441.6311 L 4078.5142 3441.3412 L 4077.9343 3441.3412 L 4077.6444 3441.6311 L 4077.503 3442.0695 L 4077.4959 3442.3595 L 4077.6444 3442.7908 L 4078.2243 3443.9504 L 4078.3728 3444.3818 L 4078.3657 3444.6717 L 4078.2172 3445.103 L 4077.7859 3445.5344 L 4077.2131 3445.5414 L 4076.6333 3445.2445 L 4076.0534 3444.6646 L 4075.7635 3444.0919 L 4075.7635 3443.512 M 4080.7698 3444.7565 L 4080.9113 3444.6151 L 4081.3426 3444.4666 L 4081.6396 3444.4666 L 4082.0709 3444.6151 L 4082.6508 3445.195 L 4082.7922 3445.6192 L 4082.7922 3445.9162 L 4082.6437 3446.3475 L 4082.3538 3446.6375 L 4081.9224 3446.7859 L 4081.2012 3446.9274 L 4078.3091 3446.9203 L 4080.3385 3448.9497 M 4085.0478 3447.592 L 4084.4751 3447.3021 L 4084.0367 3447.4436 L 4083.7468 3447.7335 L 4083.6053 3448.1719 L 4083.7468 3448.6103 L 4084.1781 3449.3245 L 4084.4751 3449.9043 L 4084.4751 3450.4841 L 4084.3266 3450.9154 L 4083.8882 3451.3539 L 4083.4569 3451.5023 L 4083.1669 3451.4953 L 4082.5942 3451.2054 L 4082.0144 3450.6255 L 4081.7244 3450.0528 L 4081.7174 3449.7629 L 4081.8659 3449.3315 L 4082.3043 3448.8931 L 4082.7356 3448.7446 L 4083.3154 3448.7446 L 4083.8953 3449.0416 L 4084.6094 3449.473 L 4085.0478 3449.6144 L 4085.4862 3449.473 L 4085.7762 3449.183 L 4085.9176 3448.7446 L 4085.6277 3448.1719 L 4085.0478 3447.592 M 4086.7237 3450.4275 L 4087.1621 3450.569 L 4088.0248 3450.569 L 4084.9913 3453.6025 M 4088.4066 3452.3933 L 4088.548 3452.2519 L 4088.9794 3452.1034 L 4089.2763 3452.1034 L 4089.7077 3452.2519 L 4090.2875 3452.8317 L 4090.4289 3453.256 L 4090.4289 3453.553 L 4090.2804 3453.9843 L 4089.9905 3454.2742 L 4089.5592 3454.4227 L 4088.8379 3454.5641 L 4085.9459 3454.557 L 4087.9753 3456.5864 M 4091.9633 3454.5076 L 4088.9299 3457.541 M 4091.9633 3454.5076 L 4093.2644 3455.8086 L 4093.5543 3456.3814 L 4093.5543 3456.6784 L 4093.4058 3457.1097 L 4093.1159 3457.3996 L 4092.6846 3457.5481 L 4092.3947 3457.541 L 4091.8219 3457.2511 M 4090.5208 3455.95 L 4091.8219 3457.2511 L 4092.1048 3457.831 L 4092.1118 3458.1209 L 4091.9633 3458.5522 L 4091.5249 3458.9906 L 4091.0936 3459.1391 L 4090.8037 3459.132 L 4090.2309 3458.8421 L 4088.9299 3457.541 M 4093.2079 3459.2169 L 4095.81 3461.819 M 4098.497 3461.0412 L 4095.4635 3464.0747 M 4098.497 3461.0412 L 4096.6232 3465.2344 M 4100.8163 3463.3605 L 4096.6232 3465.2344 M 4100.8163 3463.3605 L 4097.7828 3466.394 M 4101.7709 3464.3151 L 4098.7374 3467.3486 M 4102.7255 3465.2697 L 4099.692 3468.3032 M 4102.7255 3465.2697 L 4101.7144 3470.3255 M 4104.7478 3467.292 L 4101.7144 3470.3255 M 4105.7024 3468.2466 L 4102.6689 3471.2801","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4066.9755,3394.6024 4064.788,3394.6024"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4060.212,3394.6024 4058.0246,3394.6024"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4056.3976,3390.149 4056.3976,3386.851"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4058.0246,3382.3976 4060.212,3382.3976"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4064.788,3382.3976 4066.9755,3382.3976"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4068.6024,3386.851 4068.6024,3390.149"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4066.437,3384.563 4066.437,3392.437 4058.563,3392.437 4058.563,3384.563 4066.437,3384.563"},{"type":"circle","_svgpath":"M 4062.5, 3388.5 m -2.756, 0 a 2.756,2.756 0 1,0 5.512,0 a 2.756,2.756 0 1,0 -5.512,0","start":[4062.5,3388.5],"radius":2.756,"width":"1","net":""},{"type":"text","svgpath":"M 4063.382 3407.61 L 4063.382 3403.31 M 4063.382 3407 L 4062.972 3407.4 L 4062.562 3407.61 L 4061.952 3407.61 L 4061.542 3407.4 L 4061.132 3407 L 4060.932 3406.38 L 4060.932 3405.97 L 4061.132 3405.36 L 4061.542 3404.95 L 4061.952 3404.75 L 4062.562 3404.75 L 4062.972 3404.95 L 4063.382 3405.36 M 4057.122 3407.61 L 4057.122 3404.34 L 4057.332 3403.72 L 4057.532 3403.52 L 4057.942 3403.31 L 4058.552 3403.31 L 4058.962 3403.52 M 4057.122 3407 L 4057.532 3407.4 L 4057.942 3407.61 L 4058.552 3407.61 L 4058.962 3407.4 L 4059.372 3407 L 4059.582 3406.38 L 4059.582 3405.97 L 4059.372 3405.36 L 4058.962 3404.95 L 4058.552 3404.75 L 4057.942 3404.75 L 4057.532 3404.95 L 4057.122 3405.36","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3984.322,3398.3992 3980.5469,3398.3992 3980.5469,3403.6008 3984.322,3403.6008"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3987.678,3398.3992 3991.4531,3398.3992 3991.4531,3403.6008 3987.678,3403.6008"},{"type":"text","svgpath":"M 3986 3415.72L3985.59 3415.93 L3984.98 3416.54 L3984.98 3412.25 M 3982.4 3416.54L3983.01 3416.34 L3983.42 3415.72 L3983.63 3414.7 L3983.63 3414.09 L3983.42 3413.06 L3983.01 3412.45 L3982.4 3412.25 L3981.99 3412.25 L3981.38 3412.45 L3980.97 3413.06 L3980.76 3414.09 L3980.76 3414.7 L3980.97 3415.72 L3981.38 3416.34 L3981.99 3416.54 L3982.4 3416.54 M 3979.41 3416.54L3979.41 3412.25 M 3977.37 3415.11L3979.41 3413.06 M 3978.6 3413.88L3977.16 3412.25 ","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4032.7409,3440.003 4029.5912,3440.003"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4033.9608,3435.6339 4033.9608,3438.7834"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4028.3716,3435.6339 4028.3716,3438.7834"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4033.9837,3433.3666 4033.9837,3430.217"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4032.7639,3428.9972 4029.6144,3428.9972"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4028.3947,3433.3666 4028.3947,3430.217"},{"type":"arc","width":1,"svgpath":"M 4032.7639 3428.997 A 1.2198 1.2198 0 0 1 4033.9837 3430.2168","net":""},{"type":"arc","width":1,"svgpath":"M 4028.3945 3430.2168 A 1.2198 1.2198 0 0 1 4029.6144 3428.997","net":""},{"type":"arc","width":1,"svgpath":"M 4033.9608 3438.7832 A 1.2198 1.2198 0 0 1 4032.7409 3440.003","net":""},{"type":"arc","width":1,"svgpath":"M 4029.5914 3440.003 A 1.2198 1.2198 0 0 1 4028.3716 3438.7832","net":""},{"type":"text","svgpath":"M 4045.887 3433.5305 L 4046.097 3433.9405 L 4046.707 3434.5505 L 4042.417 3434.5505 M 4046.707 3437.1305 L 4046.507 3436.5205 L 4045.887 3436.1105 L 4044.867 3435.9005 L 4044.257 3435.9005 L 4043.227 3436.1105 L 4042.617 3436.5205 L 4042.417 3437.1305 L 4042.417 3437.5405 L 4042.617 3438.1505 L 4043.227 3438.5605 L 4044.257 3438.7705 L 4044.867 3438.7705 L 4045.887 3438.5605 L 4046.507 3438.1505 L 4046.707 3437.5405 L 4046.707 3437.1305 M 4045.277 3440.1205 L 4043.227 3440.1205 L 4042.617 3440.3205 L 4042.417 3440.7305 L 4042.417 3441.3405 L 4042.617 3441.7505 L 4043.227 3442.3705 M 4045.277 3442.3705 L 4042.417 3442.3705 M 4046.707 3443.7205 L 4042.417 3443.7205 M 4046.707 3443.7205 L 4046.707 3446.3805 M 4044.667 3443.7205 L 4044.667 3445.3505","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3991.4725,3413.9261 3991.4725,3417.0758"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3987.1034,3412.7062 3990.2529,3412.7062"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3987.1034,3418.2954 3990.2529,3418.2954"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3984.8361,3412.6833 3981.6865,3412.6833"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3980.4667,3413.9031 3980.4667,3417.0526"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3984.8361,3418.2723 3981.6865,3418.2723"},{"type":"arc","width":1,"svgpath":"M 3980.4665 3413.9031 A 1.2198 1.2198 0 0 1 3981.6863 3412.6833","net":""},{"type":"arc","width":1,"svgpath":"M 3981.6863 3418.2725 A 1.2198 1.2198 0 0 1 3980.4665 3417.0526","net":""},{"type":"arc","width":1,"svgpath":"M 3990.2527 3412.7062 A 1.2198 1.2198 0 0 1 3991.4725 3413.9261","net":""},{"type":"arc","width":1,"svgpath":"M 3991.4725 3417.0756 A 1.2198 1.2198 0 0 1 3990.2527 3418.2954","net":""},{"type":"text","svgpath":"M 3985 3400.78L3985.41 3400.57 L3986.02 3399.96 L3986.02 3404.25 M 3987.37 3401.39L3987.37 3403.44 L3987.58 3404.05 L3987.99 3404.25 L3988.6 3404.25 L3989.01 3404.05 L3989.62 3403.44 M 3989.62 3401.39L3989.62 3404.25 ","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3991.4725,3384.4261 3991.4725,3387.5758"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3987.1034,3383.2062 3990.2529,3383.2062"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3987.1034,3388.7954 3990.2529,3388.7954"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3984.8361,3383.1833 3981.6865,3383.1833"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3980.4667,3384.4031 3980.4667,3387.5526"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3984.8361,3388.7723 3981.6865,3388.7723"},{"type":"arc","width":1,"svgpath":"M 3980.4665 3384.4031 A 1.2198 1.2198 0 0 1 3981.6863 3383.1833","net":""},{"type":"arc","width":1,"svgpath":"M 3981.6863 3388.7725 A 1.2198 1.2198 0 0 1 3980.4665 3387.5526","net":""},{"type":"arc","width":1,"svgpath":"M 3990.2527 3383.2062 A 1.2198 1.2198 0 0 1 3991.4725 3384.4261","net":""},{"type":"arc","width":1,"svgpath":"M 3991.4725 3387.5756 A 1.2198 1.2198 0 0 1 3990.2527 3388.7954","net":""},{"type":"text","svgpath":"M 3985 3371.28L3985.41 3371.07 L3986.02 3370.46 L3986.02 3374.75 M 3988.6 3370.46L3987.99 3370.66 L3987.58 3371.28 L3987.37 3372.3 L3987.37 3372.91 L3987.58 3373.94 L3987.99 3374.55 L3988.6 3374.75 L3989.01 3374.75 L3989.62 3374.55 L3990.03 3373.94 L3990.24 3372.91 L3990.24 3372.3 L3990.03 3371.28 L3989.62 3370.66 L3989.01 3370.46 L3988.6 3370.46 M 3991.59 3371.89L3991.59 3373.94 L3991.79 3374.55 L3992.2 3374.75 L3992.81 3374.75 L3993.22 3374.55 L3993.84 3373.94 M 3993.84 3371.89L3993.84 3374.75 M 3995.19 3370.46L3995.19 3374.75 M 3995.19 3370.46L3997.84 3370.46 M 3995.19 3372.5L3996.82 3372.5 ","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3991.4725,3392.0061 3991.4725,3395.1558"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3987.1034,3390.7862 3990.2529,3390.7862"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3987.1034,3396.3754 3990.2529,3396.3754"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3984.8361,3390.7633 3981.6865,3390.7633"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3980.4667,3391.9831 3980.4667,3395.1326"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3984.8361,3396.3523 3981.6865,3396.3523"},{"type":"arc","width":1,"svgpath":"M 3980.4665 3391.9831 A 1.2198 1.2198 0 0 1 3981.6863 3390.7633","net":""},{"type":"arc","width":1,"svgpath":"M 3981.6863 3396.3525 A 1.2198 1.2198 0 0 1 3980.4665 3395.1326","net":""},{"type":"arc","width":1,"svgpath":"M 3990.2527 3390.7862 A 1.2198 1.2198 0 0 1 3991.4725 3392.0061","net":""},{"type":"arc","width":1,"svgpath":"M 3991.4725 3395.1556 A 1.2198 1.2198 0 0 1 3990.2527 3396.3754","net":""},{"type":"text","svgpath":"M 3985 3378.86L3985.41 3378.65 L3986.02 3378.04 L3986.02 3382.33 M 3988.6 3378.04L3987.99 3378.24 L3987.58 3378.86 L3987.37 3379.88 L3987.37 3380.49 L3987.58 3381.52 L3987.99 3382.13 L3988.6 3382.33 L3989.01 3382.33 L3989.62 3382.13 L3990.03 3381.52 L3990.24 3380.49 L3990.24 3379.88 L3990.03 3378.86 L3989.62 3378.24 L3989.01 3378.04 L3988.6 3378.04 M 3992.81 3378.04L3992.2 3378.24 L3991.79 3378.86 L3991.59 3379.88 L3991.59 3380.49 L3991.79 3381.52 L3992.2 3382.13 L3992.81 3382.33 L3993.22 3382.33 L3993.84 3382.13 L3994.25 3381.52 L3994.45 3380.49 L3994.45 3379.88 L3994.25 3378.86 L3993.84 3378.24 L3993.22 3378.04 L3992.81 3378.04 M 3995.8 3379.47L3995.8 3382.33 M 3995.8 3380.29L3996.41 3379.68 L3996.82 3379.47 L3997.44 3379.47 L3997.85 3379.68 L3998.05 3380.29 L3998.05 3382.33 ","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.315,"svgpath":"M3963.8,3396.65 3976.2,3396.65"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.315,"svgpath":"M3963.7,3390.35 3976.3,3390.35"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.315,"svgpath":"M3968.7264,3396.65 3968.7411,3390.35"},{"type":"text","svgpath":"M 3970.045 3377.88 L 3970.045 3377.68 L 3970.245 3377.27 L 3970.455 3377.06 L 3970.865 3376.86 L 3971.685 3376.86 L 3972.095 3377.06 L 3972.295 3377.27 L 3972.495 3377.68 L 3972.495 3378.09 L 3972.295 3378.5 L 3971.885 3379.11 L 3969.845 3381.15 L 3972.705 3381.15 M 3974.255 3377.88 L 3974.255 3377.68 L 3974.465 3377.27 L 3974.665 3377.06 L 3975.075 3376.86 L 3975.895 3376.86 L 3976.305 3377.06 L 3976.505 3377.27 L 3976.715 3377.68 L 3976.715 3378.09 L 3976.505 3378.5 L 3976.095 3379.11 L 3974.055 3381.15 L 3976.915 3381.15 M 3978.265 3378.29 L 3978.265 3380.34 L 3978.475 3380.95 L 3978.885 3381.15 L 3979.495 3381.15 L 3979.905 3380.95 L 3980.515 3380.34 M 3980.515 3378.29 L 3980.515 3381.15 M 3981.865 3376.86 L 3981.865 3381.15 M 3981.865 3376.86 L 3984.525 3376.86 M 3981.865 3378.9 L 3983.505 3378.9","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3978.3118,3437 3966.6882,3437"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3978.3118,3427.3103 3978.3118,3441.6897"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3966.6882,3427.3103 3966.6882,3441.6897"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3978.3118,3427.3103 3977.9773,3427.3103"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3966.6882,3427.3103 3967.0227,3427.3103"},{"type":"polygon","svgpath":"M 3978.6118 3441.3898 L 3977.7772 3441.3898 L 3977.7772 3443.1898 L 3978.6118 3443.1898 Z ","start":[0,0],"end":[0,0],"net":""},{"type":"polygon","svgpath":"M 3966.3882 3441.3898 L 3967.2228 3441.3898 L 3967.2228 3443.1898 L 3966.3882 3443.1898 Z ","start":[0,0],"end":[0,0],"net":""},{"type":"text","svgpath":"M 3991.22 3434.5 L 3991.43 3434.91 L 3992.04 3435.52 L 3987.75 3435.52 M 3992.04 3438.1 L 3991.84 3437.49 L 3991.22 3437.08 L 3990.2 3436.87 L 3989.59 3436.87 L 3988.56 3437.08 L 3987.95 3437.49 L 3987.75 3438.1 L 3987.75 3438.51 L 3987.95 3439.12 L 3988.56 3439.53 L 3989.59 3439.74 L 3990.2 3439.74 L 3991.22 3439.53 L 3991.84 3439.12 L 3992.04 3438.51 L 3992.04 3438.1 M 3990.61 3441.09 L 3988.56 3441.09 L 3987.95 3441.29 L 3987.75 3441.7 L 3987.75 3442.31 L 3987.95 3442.72 L 3988.56 3443.34 M 3990.61 3443.34 L 3987.75 3443.34 M 3992.04 3444.69 L 3987.75 3444.69 M 3992.04 3444.69 L 3992.04 3447.35 M 3990 3444.69 L 3990 3446.32","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3984.292,3405.5092 3980.5169,3405.5092 3980.5169,3410.7108 3984.292,3410.7108"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3987.648,3405.5092 3991.4231,3405.5092 3991.4231,3410.7108 3987.648,3410.7108"},{"type":"text","svgpath":"M 3980.75 3420.47L3981.16 3420.27 L3981.77 3419.65 L3981.77 3423.95 M 3984.35 3419.65L3983.73 3419.86 L3983.32 3420.47 L3983.12 3421.5 L3983.12 3422.11 L3983.32 3423.13 L3983.73 3423.75 L3984.35 3423.95 L3984.76 3423.95 L3985.37 3423.75 L3985.78 3423.13 L3985.98 3422.11 L3985.98 3421.5 L3985.78 3420.47 L3985.37 3419.86 L3984.76 3419.65 L3984.35 3419.65 M 3987.33 3419.65L3987.33 3423.95 M 3989.38 3421.09L3987.33 3423.13 M 3988.15 3422.31L3989.58 3423.95 ","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4036.3992,3436.178 4036.3992,3439.9531 4041.6008,3439.9531 4041.6008,3436.178"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4036.3992,3432.822 4036.3992,3429.0469 4041.6008,3429.0469 4041.6008,3432.822"},{"type":"text","svgpath":"M 4053.72 3434.5 L 4053.93 3434.91 L 4054.54 3435.52 L 4050.25 3435.52 M 4054.54 3438.1 L 4054.34 3437.49 L 4053.72 3437.08 L 4052.7 3436.87 L 4052.09 3436.87 L 4051.06 3437.08 L 4050.45 3437.49 L 4050.25 3438.1 L 4050.25 3438.51 L 4050.45 3439.12 L 4051.06 3439.53 L 4052.09 3439.74 L 4052.7 3439.74 L 4053.72 3439.53 L 4054.34 3439.12 L 4054.54 3438.51 L 4054.54 3438.1 M 4054.54 3441.09 L 4050.25 3441.09 M 4053.11 3443.13 L 4051.06 3441.09 M 4051.88 3441.9 L 4050.25 3443.34","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3974.512,3415.785 3978.055,3415.785 3978.055,3405.548"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3959.945,3405.548 3959.945,3415.785 3963.488,3415.785"},{"type":"circle","_svgpath":"M 3978.29, 3402.873 m -1.005, 0 a 1.005,1.005 0 1,0 2.01,0 a 1.005,1.005 0 1,0 -2.01,0","start":[3978.29,3402.873],"radius":1.005,"width":"1","net":""},{"type":"text","svgpath":"M 3945.46 3408.78 L 3949.75 3410.42 M 3945.46 3408.78 L 3949.75 3407.15 M 3948.32 3409.81 L 3948.32 3407.76 M 3945.46 3405.8 L 3949.75 3405.8 M 3945.46 3405.8 L 3949.75 3404.16 M 3945.46 3402.52 L 3949.75 3404.16 M 3945.46 3402.52 L 3949.75 3402.52 M 3946.07 3398.31 L 3945.66 3398.72 L 3945.46 3399.33 L 3945.46 3400.15 L 3945.66 3400.77 L 3946.07 3401.17 L 3946.48 3401.17 L 3946.89 3400.97 L 3947.1 3400.77 L 3947.3 3400.36 L 3947.71 3399.13 L 3947.91 3398.72 L 3948.12 3398.52 L 3948.53 3398.31 L 3949.14 3398.31 L 3949.55 3398.72 L 3949.75 3399.33 L 3949.75 3400.15 L 3949.55 3400.77 L 3949.14 3401.17 M 3946.28 3396.96 L 3946.07 3396.55 L 3945.46 3395.94 L 3949.75 3395.94 M 3946.28 3394.59 L 3946.07 3394.18 L 3945.46 3393.57 L 3949.75 3393.57 M 3946.28 3392.22 L 3946.07 3391.81 L 3945.46 3391.19 L 3949.75 3391.19 M 3945.46 3386.98 L 3949.75 3389.02 M 3945.46 3389.84 L 3945.46 3386.98 M 3946.07 3382.77 L 3945.66 3383.17 L 3945.46 3383.79 L 3945.46 3384.61 L 3945.66 3385.22 L 3946.07 3385.63 L 3946.48 3385.63 L 3946.89 3385.42 L 3947.1 3385.22 L 3947.3 3384.81 L 3947.71 3383.58 L 3947.91 3383.17 L 3948.12 3382.97 L 3948.53 3382.77 L 3949.14 3382.77 L 3949.55 3383.17 L 3949.75 3383.79 L 3949.75 3384.61 L 3949.55 3385.22 L 3949.14 3385.63 M 3947.91 3381.42 L 3947.91 3377.73 M 3945.46 3375.97 L 3945.46 3373.72 L 3947.1 3374.95 L 3947.1 3374.34 L 3947.3 3373.93 L 3947.5 3373.72 L 3948.12 3373.52 L 3948.53 3373.52 L 3949.14 3373.72 L 3949.55 3374.13 L 3949.75 3374.75 L 3949.75 3375.36 L 3949.55 3375.97 L 3949.35 3376.18 L 3948.94 3376.38 M 3948.73 3371.97 L 3948.94 3372.17 L 3949.14 3371.97 L 3948.94 3371.76 L 3948.73 3371.97 M 3945.46 3370 L 3945.46 3367.75 L 3947.1 3368.98 L 3947.1 3368.37 L 3947.3 3367.96 L 3947.5 3367.75 L 3948.12 3367.55 L 3948.53 3367.55 L 3949.14 3367.75 L 3949.55 3368.16 L 3949.75 3368.77 L 3949.75 3369.39 L 3949.55 3370 L 3949.35 3370.21 L 3948.94 3370.41","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4001.0548,3440.5087 4006.773,3440.5087 4006.773,3436.4472"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4001.0548,3428.4913 4006.773,3428.4913 4006.773,3432.5528"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4001.0548,3436.2929 4001.0548,3432.7071"},{"type":"text","svgpath":"M 3944.9238 3448.9201 L 3944.5138 3448.5101 L 3943.9038 3448.3101 L 3943.0838 3448.3101 L 3942.4738 3448.5101 L 3942.0638 3448.9201 L 3942.0638 3449.3301 L 3942.2638 3449.7401 L 3942.4738 3449.9501 L 3942.8838 3450.1501 L 3944.1138 3450.5601 L 3944.5138 3450.7601 L 3944.7238 3450.9701 L 3944.9238 3451.3801 L 3944.9238 3451.9901 L 3944.5138 3452.4001 L 3943.9038 3452.6001 L 3943.0838 3452.6001 L 3942.4738 3452.4001 L 3942.0638 3451.9901 M 3947.3038 3448.3101 L 3946.6838 3448.5101 L 3946.4838 3448.9201 L 3946.4838 3449.3301 L 3946.6838 3449.7401 L 3947.0938 3449.9501 L 3947.9138 3450.1501 L 3948.5238 3450.3501 L 3948.9338 3450.7601 L 3949.1438 3451.1701 L 3949.1438 3451.7901 L 3948.9338 3452.2001 L 3948.7338 3452.4001 L 3948.1138 3452.6001 L 3947.3038 3452.6001 L 3946.6838 3452.4001 L 3946.4838 3452.2001 L 3946.2738 3451.7901 L 3946.2738 3451.1701 L 3946.4838 3450.7601 L 3946.8938 3450.3501 L 3947.5038 3450.1501 L 3948.3238 3449.9501 L 3948.7338 3449.7401 L 3948.9338 3449.3301 L 3948.9338 3448.9201 L 3948.7338 3448.5101 L 3948.1138 3448.3101 L 3947.3038 3448.3101 M 3951.7138 3448.3101 L 3951.1038 3448.5101 L 3950.6938 3449.1301 L 3950.4938 3450.1501 L 3950.4938 3450.7601 L 3950.6938 3451.7901 L 3951.1038 3452.4001 L 3951.7138 3452.6001 L 3952.1238 3452.6001 L 3952.7438 3452.4001 L 3953.1538 3451.7901 L 3953.3538 3450.7601 L 3953.3538 3450.1501 L 3953.1538 3449.1301 L 3952.7438 3448.5101 L 3952.1238 3448.3101 L 3951.7138 3448.3101 M 3957.1638 3448.3101 L 3955.1138 3448.3101 L 3954.9138 3450.1501 L 3955.1138 3449.9501 L 3955.7238 3449.7401 L 3956.3438 3449.7401 L 3956.9538 3449.9501 L 3957.3638 3450.3501 L 3957.5638 3450.9701 L 3957.5638 3451.3801 L 3957.3638 3451.9901 L 3956.9538 3452.4001 L 3956.3438 3452.6001 L 3955.7238 3452.6001 L 3955.1138 3452.4001 L 3954.9138 3452.2001 L 3954.7038 3451.7901 M 3960.1438 3448.3101 L 3959.5338 3448.5101 L 3959.1238 3449.1301 L 3958.9138 3450.1501 L 3958.9138 3450.7601 L 3959.1238 3451.7901 L 3959.5338 3452.4001 L 3960.1438 3452.6001 L 3960.5538 3452.6001 L 3961.1638 3452.4001 L 3961.5738 3451.7901 L 3961.7838 3450.7601 L 3961.7838 3450.1501 L 3961.5738 3449.1301 L 3961.1638 3448.5101 L 3960.5538 3448.3101 L 3960.1438 3448.3101 M 3963.1338 3450.7601 L 3966.8138 3450.7601 M 3971.2338 3449.3301 L 3971.0238 3448.9201 L 3970.6138 3448.5101 L 3970.2138 3448.3101 L 3969.3938 3448.3101 L 3968.9838 3448.5101 L 3968.5738 3448.9201 L 3968.3638 3449.3301 L 3968.1638 3449.9501 L 3968.1638 3450.9701 L 3968.3638 3451.5801 L 3968.5738 3451.9901 L 3968.9838 3452.4001 L 3969.3938 3452.6001 L 3970.2138 3452.6001 L 3970.6138 3452.4001 L 3971.0238 3451.9901 L 3971.2338 3451.5801 L 3971.2338 3450.9701 M 3970.2138 3450.9701 L 3971.2338 3450.9701 M 3972.5838 3454.0401 L 3976.2638 3454.0401 M 3980.6838 3449.3301 L 3980.4738 3448.9201 L 3980.0638 3448.5101 L 3979.6638 3448.3101 L 3978.8438 3448.3101 L 3978.4338 3448.5101 L 3978.0238 3448.9201 L 3977.8138 3449.3301 L 3977.6138 3449.9501 L 3977.6138 3450.9701 L 3977.8138 3451.5801 L 3978.0238 3451.9901 L 3978.4338 3452.4001 L 3978.8438 3452.6001 L 3979.6638 3452.6001 L 3980.0638 3452.4001 L 3980.4738 3451.9901 L 3980.6838 3451.5801 M 3982.0338 3449.1301 L 3982.4438 3448.9201 L 3983.0538 3448.3101 L 3983.0538 3452.6001 M 3986.8638 3448.9201 L 3986.6538 3448.5101 L 3986.0438 3448.3101 L 3985.6338 3448.3101 L 3985.0138 3448.5101 L 3984.6138 3449.1301 L 3984.4038 3450.1501 L 3984.4038 3451.1701 L 3984.6138 3451.9901 L 3985.0138 3452.4001 L 3985.6338 3452.6001 L 3985.8338 3452.6001 L 3986.4538 3452.4001 L 3986.8638 3451.9901 L 3987.0638 3451.3801 L 3987.0638 3451.1701 L 3986.8638 3450.5601 L 3986.4538 3450.1501 L 3985.8338 3449.9501 L 3985.6338 3449.9501 L 3985.0138 3450.1501 L 3984.6138 3450.5601 L 3984.4038 3451.1701 M 3990.4638 3448.3101 L 3988.4138 3451.1701 L 3991.4838 3451.1701 M 3990.4638 3448.3101 L 3990.4638 3452.6001 M 3993.8538 3448.3101 L 3993.2438 3448.5101 L 3993.0338 3448.9201 L 3993.0338 3449.3301 L 3993.2438 3449.7401 L 3993.6538 3449.9501 L 3994.4638 3450.1501 L 3995.0838 3450.3501 L 3995.4938 3450.7601 L 3995.6938 3451.1701 L 3995.6938 3451.7901 L 3995.4938 3452.2001 L 3995.2838 3452.4001 L 3994.6738 3452.6001 L 3993.8538 3452.6001 L 3993.2438 3452.4001 L 3993.0338 3452.2001 L 3992.8338 3451.7901 L 3992.8338 3451.1701 L 3993.0338 3450.7601 L 3993.4438 3450.3501 L 3994.0638 3450.1501 L 3994.8738 3449.9501 L 3995.2838 3449.7401 L 3995.4938 3449.3301 L 3995.4938 3448.9201 L 3995.2838 3448.5101 L 3994.6738 3448.3101 L 3993.8538 3448.3101 M 3999.7038 3449.7401 L 3999.5038 3450.3501 L 3999.0938 3450.7601 L 3998.4738 3450.9701 L 3998.2738 3450.9701 L 3997.6638 3450.7601 L 3997.2538 3450.3501 L 3997.0438 3449.7401 L 3997.0438 3449.5401 L 3997.2538 3448.9201 L 3997.6638 3448.5101 L 3998.2738 3448.3101 L 3998.4738 3448.3101 L 3999.0938 3448.5101 L 3999.5038 3448.9201 L 3999.7038 3449.7401 L 3999.7038 3450.7601 L 3999.5038 3451.7901 L 3999.0938 3452.4001 L 3998.4738 3452.6001 L 3998.0638 3452.6001 L 3997.4538 3452.4001 L 3997.2538 3451.9901 M 4001.2638 3449.3301 L 4001.2638 3449.1301 L 4001.4638 3448.7201 L 4001.6638 3448.5101 L 4002.0738 3448.3101 L 4002.8938 3448.3101 L 4003.3038 3448.5101 L 4003.5138 3448.7201 L 4003.7138 3449.1301 L 4003.7138 3449.5401 L 4003.5138 3449.9501 L 4003.1038 3450.5601 L 4001.0538 3452.6001 L 4003.9138 3452.6001","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4045.9843,3422.5472 4045.9844,3357.1927"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4045.9844,3378.4528 3994.0156,3378.4528"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3994.0156,3357.1928 4045.9844,3357.1928"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3994.0157,3422.5472 3994.0156,3357.1928"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3994.0157,3422.5472 4045.9843,3422.5472"},{"type":"circle","_svgpath":"M 3992.441, 3384.752 m -0.394, 0 a 0.394,0.394 0 1,0 0.788,0 a 0.394,0.394 0 1,0 -0.788,0","start":[3992.441,3384.752],"radius":0.394,"width":"1","net":""},{"type":"text","svgpath":"M 4018 3343.96 L 4018 3348.25 M 4018 3343.96 L 4020.66 3343.96 M 4018 3346 L 4019.64 3346 M 4018 3348.25 L 4020.66 3348.25 M 4024.87 3344.57 L 4024.46 3344.16 L 4023.85 3343.96 L 4023.03 3343.96 L 4022.42 3344.16 L 4022.01 3344.57 L 4022.01 3344.98 L 4022.21 3345.39 L 4022.42 3345.6 L 4022.83 3345.8 L 4024.05 3346.21 L 4024.46 3346.41 L 4024.67 3346.62 L 4024.87 3347.03 L 4024.87 3347.64 L 4024.46 3348.05 L 4023.85 3348.25 L 4023.03 3348.25 L 4022.42 3348.05 L 4022.01 3347.64 M 4026.22 3343.96 L 4026.22 3348.25 M 4026.22 3343.96 L 4028.06 3343.96 L 4028.68 3344.16 L 4028.88 3344.37 L 4029.09 3344.78 L 4029.09 3345.39 L 4028.88 3345.8 L 4028.68 3346 L 4028.06 3346.21 L 4026.22 3346.21 M 4030.85 3343.96 L 4033.1 3343.96 L 4031.87 3345.6 L 4032.48 3345.6 L 4032.89 3345.8 L 4033.1 3346 L 4033.3 3346.62 L 4033.3 3347.03 L 4033.1 3347.64 L 4032.69 3348.05 L 4032.07 3348.25 L 4031.46 3348.25 L 4030.85 3348.05 L 4030.64 3347.85 L 4030.44 3347.44 M 4034.85 3344.98 L 4034.85 3344.78 L 4035.06 3344.37 L 4035.26 3344.16 L 4035.67 3343.96 L 4036.49 3343.96 L 4036.9 3344.16 L 4037.1 3344.37 L 4037.31 3344.78 L 4037.31 3345.19 L 4037.1 3345.6 L 4036.7 3346.21 L 4034.65 3348.25 L 4037.51 3348.25 M 4038.86 3346.41 L 4042.55 3346.41 M 4046.96 3344.98 L 4046.76 3344.57 L 4046.35 3344.16 L 4045.94 3343.96 L 4045.12 3343.96 L 4044.71 3344.16 L 4044.3 3344.57 L 4044.1 3344.98 L 4043.9 3345.6 L 4043.9 3346.62 L 4044.1 3347.23 L 4044.3 3347.64 L 4044.71 3348.05 L 4045.12 3348.25 L 4045.94 3348.25 L 4046.35 3348.05 L 4046.76 3347.64 L 4046.96 3347.23 M 4048.72 3343.96 L 4050.97 3343.96 L 4049.75 3345.6 L 4050.36 3345.6 L 4050.77 3345.8 L 4050.97 3346 L 4051.18 3346.62 L 4051.18 3347.03 L 4050.97 3347.64 L 4050.56 3348.05 L 4049.95 3348.25 L 4049.34 3348.25 L 4048.72 3348.05 L 4048.52 3347.85 L 4048.31 3347.44 M 4052.53 3346.41 L 4056.21 3346.41 M 4057.56 3343.96 L 4057.56 3348.25 M 4057.56 3343.96 L 4059.2 3348.25 M 4060.83 3343.96 L 4059.2 3348.25 M 4060.83 3343.96 L 4060.83 3348.25 M 4062.18 3343.96 L 4062.18 3348.25 M 4063.53 3343.96 L 4063.53 3348.25 M 4063.53 3343.96 L 4066.4 3348.25 M 4066.4 3343.96 L 4066.4 3348.25 M 4067.75 3343.96 L 4067.75 3348.25 M 4069.1 3346.41 L 4072.78 3346.41 M 4074.13 3344.78 L 4074.54 3344.57 L 4075.15 3343.96 L 4075.15 3348.25 M 4076.5 3346.41 L 4080.18 3346.41 M 4081.53 3343.96 L 4081.53 3348.25 M 4081.53 3343.96 L 4084.4 3348.25 M 4084.4 3343.96 L 4084.4 3348.25 M 4087.79 3343.96 L 4085.75 3346.82 L 4088.81 3346.82 M 4087.79 3343.96 L 4087.79 3348.25","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"text","svgpath":"M 4018 3350.96 L 4018 3354.03 L 4018.2 3354.64 L 4018.61 3355.05 L 4019.23 3355.25 L 4019.64 3355.25 L 4020.25 3355.05 L 4020.66 3354.64 L 4020.86 3354.03 L 4020.86 3350.96 M 4022.21 3351.78 L 4022.62 3351.57 L 4023.24 3350.96 L 4023.24 3355.25","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","ref":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4024.7132,3440.003 4021.5635,3440.003"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4025.9331,3435.6339 4025.9331,3438.7834"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4020.3439,3435.6339 4020.3439,3438.7834"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4025.956,3433.3666 4025.956,3430.217"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4024.7362,3428.9972 4021.5867,3428.9972"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4020.367,3433.3666 4020.367,3430.217"},{"type":"arc","width":1,"svgpath":"M 4024.7362 3428.997 A 1.2198 1.2198 0 0 1 4025.956 3430.2168","net":""},{"type":"arc","width":1,"svgpath":"M 4020.3668 3430.2168 A 1.2198 1.2198 0 0 1 4021.5867 3428.997","net":""},{"type":"arc","width":1,"svgpath":"M 4025.9331 3438.7832 A 1.2198 1.2198 0 0 1 4024.7132 3440.003","net":""},{"type":"arc","width":1,"svgpath":"M 4021.5637 3440.003 A 1.2198 1.2198 0 0 1 4020.3439 3438.7832","net":""},{"type":"text","svgpath":"M 4038.3593 3433.5605 L 4038.5693 3433.9705 L 4039.1793 3434.5805 L 4034.8893 3434.5805 M 4039.1793 3437.1605 L 4038.9793 3436.5505 L 4038.3593 3436.1405 L 4037.3393 3435.9305 L 4036.7293 3435.9305 L 4035.6993 3436.1405 L 4035.0893 3436.5505 L 4034.8893 3437.1605 L 4034.8893 3437.5705 L 4035.0893 3438.1805 L 4035.6993 3438.5905 L 4036.7293 3438.8005 L 4037.3393 3438.8005 L 4038.3593 3438.5905 L 4038.9793 3438.1805 L 4039.1793 3437.5705 L 4039.1793 3437.1605 M 4039.1793 3441.3705 L 4038.9793 3440.7605 L 4038.3593 3440.3505 L 4037.3393 3440.1505 L 4036.7293 3440.1505 L 4035.6993 3440.3505 L 4035.0893 3440.7605 L 4034.8893 3441.3705 L 4034.8893 3441.7805 L 4035.0893 3442.4005 L 4035.6993 3442.8105 L 4036.7293 3443.0105 L 4037.3393 3443.0105 L 4038.3593 3442.8105 L 4038.9793 3442.4005 L 4039.1793 3441.7805 L 4039.1793 3441.3705 M 4037.7493 3444.3605 L 4034.8893 3444.3605 M 4036.9293 3444.3605 L 4037.5393 3444.9705 L 4037.7493 3445.3805 L 4037.7493 3446.0005 L 4037.5393 3446.4105 L 4036.9293 3446.6105 L 4034.8893 3446.6105","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4012.7269,3436.178 4012.7269,3439.9531 4017.9285,3439.9531 4017.9285,3436.178"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M4012.7269,3432.822 4012.7269,3429.0469 4017.9285,3429.0469 4017.9285,3432.822"},{"type":"text","svgpath":"M 4030.3477 3434.49 L 4030.5477 3434.9 L 4031.1577 3435.51 L 4026.8677 3435.51 M 4031.1577 3438.09 L 4030.9577 3437.47 L 4030.3477 3437.07 L 4029.3177 3436.86 L 4028.7077 3436.86 L 4027.6877 3437.07 L 4027.0677 3437.47 L 4026.8677 3438.09 L 4026.8677 3438.5 L 4027.0677 3439.11 L 4027.6877 3439.52 L 4028.7077 3439.72 L 4029.3177 3439.72 L 4030.3477 3439.52 L 4030.9577 3439.11 L 4031.1577 3438.5 L 4031.1577 3438.09","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3995.1008,3432.822 3995.1008,3429.0469 3989.8992,3429.0469 3989.8992,3432.822"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.6,"svgpath":"M3995.1008,3436.178 3995.1008,3439.9531 3989.8992,3439.9531 3989.8992,3436.178"},{"type":"text","svgpath":"M 3977.48 3434.51 L 3977.28 3434.1 L 3976.67 3433.49 L 3980.96 3433.49 M 3976.67 3432.14 L 3980.96 3432.14 M 3976.67 3429.28 L 3979.53 3432.14 M 3978.51 3431.12 L 3980.96 3429.28","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"text","svgpath":"M 4064.206 3429.034 L 4071.836 3426.124 M 4064.206 3423.214 L 4071.836 3426.124 M 4066.026 3420.454 L 4065.656 3420.454 L 4064.926 3420.084 L 4064.566 3419.724 L 4064.206 3418.994 L 4064.206 3417.544 L 4064.566 3416.814 L 4064.926 3416.454 L 4065.656 3416.084 L 4066.386 3416.084 L 4067.116 3416.454 L 4068.206 3417.184 L 4071.836 3420.814 L 4071.836 3415.724 M 4070.026 3412.964 L 4070.386 3413.324 L 4070.746 3412.964 L 4070.386 3412.594 L 4070.026 3412.964 M 4066.026 3409.834 L 4065.656 3409.834 L 4064.926 3409.474 L 4064.566 3409.104 L 4064.206 3408.384 L 4064.206 3406.924 L 4064.566 3406.194 L 4064.926 3405.834 L 4065.656 3405.474 L 4066.386 3405.474 L 4067.116 3405.834 L 4068.206 3406.564 L 4071.836 3410.194 L 4071.836 3405.104","useTrueTypeFontRendering":false,"thickness":0.8,"width":0.8,"net":""}],"B":[{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.591,"svgpath":"M3997.558,3462.265 3997.558,3452.029"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.591,"svgpath":"M4042.44,3490.021 4042.44,3452.226"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.591,"svgpath":"M4040.865,3450.651 4036.928,3450.651"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.591,"svgpath":"M3994.409,3490.021 3994.409,3465.415"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.591,"svgpath":"M3995.983,3491.596 4040.865,3491.596"},{"type":"polyline","net":"","start":[0,0],"end":[0,0],"width":0.591,"svgpath":"M4003.07,3450.651 3999.133,3450.651"},{"type":"arc","width":0.591,"svgpath":"M 4040.472 3467.383 A 1.968 1.968 0 1 0 4040.471 3467.404","net":""},{"type":"arc","width":0.591,"svgpath":"M 4001.102 3467.383 A 1.968 1.968 0 1 0 4001.101 3467.404","net":""},{"type":"arc","width":0.591,"svgpath":"M 3994.409 3490.021 A 1.575 1.575 0 0 0 3995.983 3491.596","net":""},{"type":"arc","width":0.591,"svgpath":"M 4040.865 3491.596 A 1.575 1.575 0 0 0 4042.44 3490.021","net":""},{"type":"arc","width":0.591,"svgpath":"M 3995.983 3463.84 A 1.575 1.575 0 0 0 3994.409 3465.415","net":""},{"type":"arc","width":0.591,"svgpath":"M 3995.983 3463.84 A 1.575 1.575 0 0 0 3997.558 3462.265","net":""},{"type":"arc","width":0.591,"svgpath":"M 4042.44 3452.226 A 1.575 1.575 0 0 0 4040.865 3450.651","net":""},{"type":"arc","width":0.591,"svgpath":"M 3999.133 3450.651 A 1.575 1.575 0 0 0 3997.558 3452.226","net":""},{"type":"text","svgpath":"M 4059.52 3470.43 L 4059.93 3470.64 L 4060.34 3471.05 L 4060.54 3471.45 L 4060.54 3472.27 L 4060.34 3472.68 L 4059.93 3473.09 L 4059.52 3473.3 L 4058.9 3473.5 L 4057.88 3473.5 L 4057.27 3473.3 L 4056.86 3473.09 L 4056.45 3472.68 L 4056.25 3472.27 L 4056.25 3471.45 L 4056.45 3471.05 L 4056.86 3470.64 L 4057.27 3470.43 L 4057.88 3470.43 M 4057.88 3471.45 L 4057.88 3470.43 M 4059.52 3466.01 L 4059.93 3466.22 L 4060.34 3466.63 L 4060.54 3467.04 L 4060.54 3467.85 L 4060.34 3468.26 L 4059.93 3468.67 L 4059.52 3468.88 L 4058.9 3469.08 L 4057.88 3469.08 L 4057.27 3468.88 L 4056.86 3468.67 L 4056.45 3468.26 L 4056.25 3467.85 L 4056.25 3467.04 L 4056.45 3466.63 L 4056.86 3466.22 L 4057.27 3466.01 M 4059.11 3462 L 4058.5 3462.21 L 4058.09 3462.62 L 4057.88 3463.23 L 4057.88 3463.44 L 4058.09 3464.05 L 4058.5 3464.46 L 4059.11 3464.66 L 4059.31 3464.66 L 4059.93 3464.46 L 4060.34 3464.05 L 4060.54 3463.44 L 4060.54 3463.23 L 4060.34 3462.62 L 4059.93 3462.21 L 4059.11 3462 L 4058.09 3462 L 4057.06 3462.21 L 4056.45 3462.62 L 4056.25 3463.23 L 4056.25 3463.64 L 4056.45 3464.25 L 4056.86 3464.46 M 4060.54 3459.02 L 4056.25 3460.65 M 4060.54 3459.02 L 4056.25 3457.38 M 4057.68 3460.04 L 4057.68 3458 M 4060.54 3454.8 L 4060.34 3455.42 L 4059.72 3455.83 L 4058.7 3456.03 L 4058.09 3456.03 L 4057.06 3455.83 L 4056.45 3455.42 L 4056.25 3454.8 L 4056.25 3454.4 L 4056.45 3453.78 L 4057.06 3453.37 L 4058.09 3453.17 L 4058.7 3453.17 L 4059.72 3453.37 L 4060.34 3453.78 L 4060.54 3454.4 L 4060.54 3454.8 M 4059.72 3451.82 L 4059.93 3451.41 L 4060.54 3450.8 L 4056.25 3450.8 M 4054.81 3449.45 L 4054.81 3445.76 M 4060.54 3444.41 L 4056.25 3444.41 M 4060.54 3443.06 L 4056.25 3443.06 M 4060.54 3443.06 L 4060.54 3441.22 L 4060.34 3440.61 L 4060.13 3440.4 L 4059.72 3440.2 L 4059.11 3440.2 L 4058.7 3440.4 L 4058.5 3440.61 L 4058.29 3441.22 L 4058.29 3443.06 M 4059.93 3435.99 L 4060.34 3436.4 L 4060.54 3437.01 L 4060.54 3437.83 L 4060.34 3438.44 L 4059.93 3438.85 L 4059.52 3438.85 L 4059.11 3438.65 L 4058.9 3438.44 L 4058.7 3438.03 L 4058.29 3436.8 L 4058.09 3436.4 L 4057.88 3436.19 L 4057.47 3435.99 L 4056.86 3435.99 L 4056.45 3436.4 L 4056.25 3437.01 L 4056.25 3437.83 L 4056.45 3438.44 L 4056.86 3438.85 M 4054.81 3434.64 L 4054.81 3430.95 M 4060.54 3427.15 L 4056.25 3427.15 M 4058.5 3427.15 L 4058.9 3427.56 L 4059.11 3427.97 L 4059.11 3428.58 L 4058.9 3428.99 L 4058.5 3429.4 L 4057.88 3429.6 L 4057.47 3429.6 L 4056.86 3429.4 L 4056.45 3428.99 L 4056.25 3428.58 L 4056.25 3427.97 L 4056.45 3427.56 L 4056.86 3427.15 M 4060.54 3425.8 L 4060.34 3425.6 L 4060.54 3425.39 L 4060.75 3425.6 L 4060.54 3425.8 M 4059.11 3425.6 L 4056.25 3425.6 M 4058.5 3421.79 L 4058.9 3422 L 4059.11 3422.61 L 4059.11 3423.22 L 4058.9 3423.84 L 4058.5 3424.04 L 4058.09 3423.84 L 4057.88 3423.43 L 4057.68 3422.4 L 4057.47 3422 L 4057.06 3421.79 L 4056.86 3421.79 L 4056.45 3422 L 4056.25 3422.61 L 4056.25 3423.22 L 4056.45 3423.84 L 4056.86 3424.04 M 4059.11 3420.44 L 4054.81 3420.44 M 4058.5 3420.44 L 4058.9 3420.03 L 4059.11 3419.62 L 4059.11 3419.01 L 4058.9 3418.6 L 4058.5 3418.19 L 4057.88 3417.99 L 4057.47 3417.99 L 4056.86 3418.19 L 4056.45 3418.6 L 4056.25 3419.01 L 4056.25 3419.62 L 4056.45 3420.03 L 4056.86 3420.44 M 4060.54 3416.64 L 4056.25 3416.64 M 4059.11 3412.83 L 4056.25 3412.83 M 4058.5 3412.83 L 4058.9 3413.24 L 4059.11 3413.65 L 4059.11 3414.26 L 4058.9 3414.67 L 4058.5 3415.08 L 4057.88 3415.29 L 4057.47 3415.29 L 4056.86 3415.08 L 4056.45 3414.67 L 4056.25 3414.26 L 4056.25 3413.65 L 4056.45 3413.24 L 4056.86 3412.83 M 4059.11 3411.28 L 4056.25 3410.05 M 4059.11 3408.82 L 4056.25 3410.05 L 4055.43 3410.46 L 4055.02 3410.87 L 4054.81 3411.28 L 4054.81 3411.48 M 4054.81 3407.47 L 4054.81 3403.79 M 4059.93 3399.58 L 4060.34 3399.99 L 4060.54 3400.6 L 4060.54 3401.42 L 4060.34 3402.03 L 4059.93 3402.44 L 4059.52 3402.44 L 4059.11 3402.24 L 4058.9 3402.03 L 4058.7 3401.62 L 4058.29 3400.4 L 4058.09 3399.99 L 4057.88 3399.78 L 4057.47 3399.58 L 4056.86 3399.58 L 4056.45 3399.99 L 4056.25 3400.6 L 4056.25 3401.42 L 4056.45 3402.03 L 4056.86 3402.44 M 4060.54 3398.23 L 4056.25 3398.23 M 4060.54 3398.23 L 4060.54 3396.39 L 4060.34 3395.77 L 4060.13 3395.57 L 4059.72 3395.36 L 4059.11 3395.36 L 4058.7 3395.57 L 4058.5 3395.77 L 4058.29 3396.39 L 4058.29 3398.23 M 4060.54 3394.01 L 4056.25 3394.01","useTrueTypeFontRendering":false,"thickness":0.6,"width":0.6,"net":"","val":1},{"type":"text","svgpath":"M 4031.615 3464.679 L 4031.795 3464.769 L 4032.065 3465.039 L 4032.065 3463.159 M 4032.745 3464.589 L 4032.745 3464.679 L 4032.825 3464.859 L 4032.915 3464.949 L 4033.095 3465.039 L 4033.455 3465.039 L 4033.635 3464.949 L 4033.725 3464.859 L 4033.815 3464.679 L 4033.815 3464.499 L 4033.725 3464.319 L 4033.545 3464.049 L 4032.655 3463.159 L 4033.905 3463.159","useTrueTypeFontRendering":false,"thickness":0.394,"width":0.394,"net":""},{"type":"text","svgpath":"M 4004.053 3464.875 L 4004.233 3464.965 L 4004.503 3465.235 L 4004.503 3463.355","useTrueTypeFontRendering":false,"thickness":0.394,"width":0.394,"net":""}]},"fabrication":{"F":[],"B":[]}},"footprints":[{"ref":"U2","center":[4020,3472.5],"bbox":{"pos":[4020,3472.5],"angle":270,"relpos":[-23.029999999999745,-22.44000000000051],"size":[42.126000000000204,48.03099999999995]},"pads":[{"layers":["B"],"pos":[4018.621,3454.391],"size":[1.3782,9.842],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4018.621,"y":3454.391},"polygon":[{"x":4017.932,"y":3459.312},{"x":4019.31,"y":3459.312},{"x":4019.31,"y":3449.47},{"x":4017.932,"y":3449.47}],"net":"DGND"},{"layers":["B"],"pos":[4015.865,3454.391],"size":[1.3779,9.842],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4015.865,"y":3454.391},"polygon":[{"x":4015.176,"y":3459.312},{"x":4016.554,"y":3459.312},{"x":4016.554,"y":3449.47},{"x":4015.176,"y":3449.47}],"net":"DGND"},{"layers":["B"],"pos":[4013.109,3454.391],"size":[0,0],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4013.109,"y":3454.391},"polygon":[{"x":4012.42,"y":3459.312},{"x":4013.798,"y":3459.312},{"x":4013.798,"y":3449.47},{"x":4012.42,"y":3449.47}],"net":"3.3V"},{"layers":["B"],"pos":[4010.353,3454.391],"size":[0,0],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4010.353,"y":3454.391},"polygon":[{"x":4009.665,"y":3459.312},{"x":4011.042,"y":3459.312},{"x":4011.042,"y":3449.47},{"x":4009.665,"y":3449.47}],"net":"3.3V"},{"layers":["B"],"pos":[4007.598,3454.391],"size":[0,0],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4007.598,"y":3454.391},"polygon":[{"x":4006.909,"y":3459.312},{"x":4008.287,"y":3459.312},{"x":4008.287,"y":3449.47},{"x":4006.909,"y":3449.47}],"net":"LED_K"},{"layers":["B"],"pos":[4004.842,3454.391],"size":[1.3779,9.842],"angle":-180,"pin1":1,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4004.842,"y":3454.391},"polygon":[{"x":4004.153,"y":3459.312},{"x":4005.531,"y":3459.312},{"x":4005.531,"y":3449.47},{"x":4004.153,"y":3449.47}],"net":"DGND"},{"layers":["B"],"pos":[4021.377,3454.391],"size":[0,0],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4021.377,"y":3454.391},"polygon":[{"x":4020.688,"y":3459.312},{"x":4022.066,"y":3459.312},{"x":4022.066,"y":3449.47},{"x":4020.688,"y":3449.47}],"net":"DC"},{"layers":["B"],"pos":[4024.133,3454.391],"size":[0,0],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4024.133,"y":3454.391},"polygon":[{"x":4023.444,"y":3459.312},{"x":4024.822,"y":3459.312},{"x":4024.822,"y":3449.47},{"x":4023.444,"y":3449.47}],"net":"HCS"},{"layers":["B"],"pos":[4026.889,3454.391],"size":[0,0],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4026.889,"y":3454.391},"polygon":[{"x":4026.2,"y":3459.312},{"x":4027.578,"y":3459.312},{"x":4027.578,"y":3449.47},{"x":4026.2,"y":3449.47}],"net":"HCLK"},{"layers":["B"],"pos":[4029.645,3454.391],"size":[0,0],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4029.645,"y":3454.391},"polygon":[{"x":4028.956,"y":3459.312},{"x":4030.334,"y":3459.312},{"x":4030.334,"y":3449.47},{"x":4028.956,"y":3449.47}],"net":"HMOSI"},{"layers":["B"],"pos":[4032.401,3454.391],"size":[0,0],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4032.401,"y":3454.391},"polygon":[{"x":4031.712,"y":3459.312},{"x":4033.09,"y":3459.312},{"x":4033.09,"y":3449.47},{"x":4031.712,"y":3449.47}],"net":"REST"},{"layers":["B"],"pos":[4035.157,3454.391],"size":[1.3779,9.842],"angle":-180,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4035.157,"y":3454.391},"polygon":[{"x":4034.468,"y":3459.312},{"x":4035.846,"y":3459.312},{"x":4035.846,"y":3449.47},{"x":4034.468,"y":3449.47}],"net":"DGND"}],"drawings":[],"layer":"B"},{"ref":"R6","center":[4016.5,3464],"bbox":{"pos":[4016.5,3464],"angle":90,"relpos":[-5.453099999999722,-2.600800000000163],"size":[10.906200000000354,5.201600000000326]},"pads":[{"layers":["F"],"pos":[4016.5,3461.034],"size":[3.1751,3.4016],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4016.5,"y":3461.0345},"polygon":[{"x":4018.2008,"y":3462.622},{"x":4014.7992,"y":3462.622},{"x":4014.7992,"y":3459.4469},{"x":4018.2008,"y":3459.4469}],"net":"USB_D-"},{"layers":["F"],"pos":[4016.5,3466.966],"size":[3.1751,3.4016],"angle":-90,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4016.5,"y":3466.9655},"polygon":[{"x":4018.2008,"y":3465.378},{"x":4014.7992,"y":3465.378},{"x":4014.7992,"y":3468.5531},{"x":4018.2008,"y":3468.5531}],"net":"U4_2"}],"drawings":[],"layer":"F"},{"ref":"R7","center":[4023.5,3464],"bbox":{"pos":[4023.5,3464],"angle":90,"relpos":[-5.453099999999722,-2.600800000000163],"size":[10.906200000000354,5.201600000000326]},"pads":[{"layers":["F"],"pos":[4023.5,3461.034],"size":[3.1751,3.4016],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4023.5,"y":3461.0345},"polygon":[{"x":4025.2008,"y":3462.622},{"x":4021.7992,"y":3462.622},{"x":4021.7992,"y":3459.4469},{"x":4025.2008,"y":3459.4469}],"net":"USB_D+"},{"layers":["F"],"pos":[4023.5,3466.966],"size":[3.1751,3.4016],"angle":-90,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4023.5,"y":3466.9655},"polygon":[{"x":4025.2008,"y":3465.378},{"x":4021.7992,"y":3465.378},{"x":4021.7992,"y":3468.5531},{"x":4025.2008,"y":3468.5531}],"net":"U4_3"}],"drawings":[],"layer":"F"},{"ref":"C8","center":[3986,3446],"bbox":{"pos":[3986,3446],"angle":135,"relpos":[-5.533534827222411,-2.8167598632230693],"size":[11.006046339226032,5.612165101288156]},"pads":[{"layers":["F"],"pos":[3984.051,3444.051],"size":[3.1496,3.5433],"angle":-135,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3984.0516,"y":3444.0516},"polygon":[{"x":3983.9121,"y":3446.4176},{"x":3981.685,"y":3444.1905},{"x":3984.1905,"y":3441.685},{"x":3986.4176,"y":3443.9121}],"net":"VUSB"},{"layers":["F"],"pos":[3987.949,3447.949],"size":[3.1496,3.5433],"angle":-135,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3987.9484,"y":3447.9484},"polygon":[{"x":3987.8095,"y":3450.315},{"x":3985.5824,"y":3448.0879},{"x":3988.0879,"y":3445.5824},{"x":3990.315,"y":3447.8095}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"C9","center":[4053,3446],"bbox":{"pos":[4053,3446],"angle":45,"relpos":[-5.533534827220592,-2.8167598632239788],"size":[11.006046339224667,5.6121651012886105]},"pads":[{"layers":["F"],"pos":[4054.949,3444.051],"size":[3.1496,3.5433],"angle":-45,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4054.9484,"y":3444.0516},"polygon":[{"x":4052.5824,"y":3443.9121},{"x":4054.8095,"y":3441.685},{"x":4057.315,"y":3444.1905},{"x":4055.0879,"y":3446.4176}],"net":"VUSB"},{"layers":["F"],"pos":[4051.051,3447.949],"size":[3.1496,3.5433],"angle":-45,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4051.0516,"y":3447.9484},"polygon":[{"x":4048.685,"y":3447.8095},{"x":4050.9121,"y":3445.5824},{"x":4053.4176,"y":3448.0879},{"x":4051.1905,"y":3450.315}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"LED2","center":[3980,3453],"bbox":{"pos":[3980,3453],"angle":45,"relpos":[-5.829812568170837,-4.527534009259398],"size":[11.659625136341674,8.920505598059208]},"pads":[{"layers":["F"],"pos":[3975.921,3454.016],"size":[3.5433,2.7559],"angle":-45,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3975.9214,"y":3454.016},"polygon":[{"x":3973.6943,"y":3454.2945},{"x":3976.1999,"y":3451.789},{"x":3978.1486,"y":3453.7377},{"x":3975.6431,"y":3456.2433}],"net":"VUSB"},{"layers":["F"],"pos":[3978.984,3457.079],"size":[3.5433,2.7559],"angle":-45,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3978.9837,"y":3457.0782},"polygon":[{"x":3976.7568,"y":3457.3571},{"x":3979.2624,"y":3454.8515},{"x":3981.211,"y":3456.8002},{"x":3978.7056,"y":3459.3058}],"net":"LED3_4"},{"layers":["F"],"pos":[3984.079,3451.984],"size":[3.5433,2.7559],"angle":-45,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3984.0782,"y":3451.9837},"polygon":[{"x":3981.8515,"y":3452.2624},{"x":3984.3571,"y":3449.7568},{"x":3986.3057,"y":3451.7055},{"x":3983.8002,"y":3454.2111}],"net":"DGND"},{"layers":["F"],"pos":[3981.016,3448.921],"size":[3.5433,2.7559],"angle":-45,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3981.0159,"y":3448.9215},"polygon":[{"x":3978.789,"y":3449.1998},{"x":3981.2944,"y":3446.6942},{"x":3983.2432,"y":3448.643},{"x":3980.7378,"y":3451.1486}],"net":"IO0"}],"drawings":[],"layer":"F"},{"ref":"LED3","center":[4060,3453],"bbox":{"pos":[4060,3453],"angle":315,"relpos":[-5.829812568171292,-4.527534009259398],"size":[11.659625136341674,8.920505598059208]},"pads":[{"layers":["F"],"pos":[4058.984,3448.921],"size":[3.5433,2.7559],"angle":-315,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4058.984,"y":3448.9214},"polygon":[{"x":4058.7054,"y":3446.6943},{"x":4061.211,"y":3449.1999},{"x":4059.2623,"y":3451.1486},{"x":4056.7567,"y":3448.643}],"net":"VUSB"},{"layers":["F"],"pos":[4055.921,3451.984],"size":[3.5433,2.7559],"angle":-315,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4055.9218,"y":3451.9837},"polygon":[{"x":4055.6429,"y":3449.7568},{"x":4058.1485,"y":3452.2623},{"x":4056.1998,"y":3454.2111},{"x":4053.6942,"y":3451.7055}],"net":""},{"layers":["F"],"pos":[4061.016,3457.079],"size":[3.5433,2.7559],"angle":-315,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4061.0163,"y":3457.0782},"polygon":[{"x":4060.7377,"y":3454.8515},{"x":4063.2432,"y":3457.3571},{"x":4061.2945,"y":3459.3058},{"x":4058.7889,"y":3456.8002}],"net":"DGND"},{"layers":["F"],"pos":[4064.079,3454.016],"size":[3.5433,2.7559],"angle":-315,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4064.0785,"y":3454.0159},"polygon":[{"x":4063.8002,"y":3451.7889},{"x":4066.3058,"y":3454.2945},{"x":4064.357,"y":3456.2433},{"x":4061.8514,"y":3453.7377}],"net":"LED3_4"}],"drawings":[],"layer":"F"},{"ref":"SW1","center":[4062.5,3388.5],"bbox":{"pos":[4062.5,3388.5],"angle":180,"relpos":[-8.759950000000572,-7.086999999999989],"size":[17.519900000000234,14.174000000000433]},"pads":[{"layers":["F"],"pos":[4069.882,3392.831],"size":[2.7559,4.9213],"angle":-270,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4069.882,"y":3392.8308},"polygon":[{"x":4072.3426,"y":3391.4528},{"x":4072.3426,"y":3394.2088},{"x":4067.4214,"y":3394.2088},{"x":4067.4214,"y":3391.4528}],"net":""},{"layers":["F"],"pos":[4055.118,3392.831],"size":[2.7559,4.9213],"angle":-270,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4055.1181,"y":3392.8307},"polygon":[{"x":4057.5787,"y":3391.4527},{"x":4057.5787,"y":3394.2087},{"x":4052.6575,"y":3394.2087},{"x":4052.6575,"y":3391.4527}],"net":"IO9"},{"layers":["F"],"pos":[4055.118,3384.169],"size":[2.7559,4.9213],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4055.1181,"y":3384.1693},"polygon":[{"x":4057.5787,"y":3382.7913},{"x":4057.5787,"y":3385.5473},{"x":4052.6575,"y":3385.5473},{"x":4052.6575,"y":3382.7913}],"net":"DGND"},{"layers":["F"],"pos":[4069.882,3384.169],"size":[2.7559,4.9213],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4069.882,"y":3384.1692},"polygon":[{"x":4072.3426,"y":3382.7912},{"x":4072.3426,"y":3385.5472},{"x":4067.4214,"y":3385.5472},{"x":4067.4214,"y":3382.7912}],"net":"DGND"},{"layers":["F"],"pos":[4062.5,3394.898],"size":[2.7559,1.378],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4062.5,"y":3394.8976},"polygon":[{"x":4061.122,"y":3394.2086},{"x":4063.878,"y":3394.2086},{"x":4063.878,"y":3395.5866},{"x":4061.122,"y":3395.5866}],"net":""},{"layers":["F"],"pos":[4062.5,3382.102],"size":[2.7559,1.378],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4062.5,"y":3382.1024},"polygon":[{"x":4061.122,"y":3381.4134},{"x":4063.878,"y":3381.4134},{"x":4063.878,"y":3382.7914},{"x":4061.122,"y":3382.7914}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"R5","center":[3986,3401],"bbox":{"pos":[3986,3401],"angle":180,"relpos":[-5.4531000000006316,-2.6007999999997082],"size":[10.906200000000354,5.201600000000326]},"pads":[{"layers":["F"],"pos":[3983.034,3401],"size":[3.1751,3.4016],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3983.0345,"y":3401},"polygon":[{"x":3984.622,"y":3399.2992},{"x":3984.622,"y":3402.7008},{"x":3981.4469,"y":3402.7008},{"x":3981.4469,"y":3399.2992}],"net":"3.3V"},{"layers":["F"],"pos":[3988.966,3401],"size":[3.1751,3.4016],"angle":-180,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3988.9655,"y":3401},"polygon":[{"x":3987.378,"y":3399.2992},{"x":3987.378,"y":3402.7008},{"x":3990.5531,"y":3402.7008},{"x":3990.5531,"y":3399.2992}],"net":"IO2"}],"drawings":[],"layer":"F"},{"ref":"C2","center":[4031.167,3434.5305],"bbox":{"pos":[4031.167,3434.5305],"angle":270,"relpos":[-5.533500004104553,-2.81670000000031],"size":[11.006000008209412,5.612100000000282]},"pads":[{"layers":["F"],"pos":[4031.167,3437.286],"size":[3.1496,3.5433],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4031.1669,"y":3437.286},"polygon":[{"x":4032.9387,"y":3435.7116},{"x":4032.9387,"y":3438.8612},{"x":4029.3953,"y":3438.8612},{"x":4029.3953,"y":3435.7116}],"net":"3.3V"},{"layers":["F"],"pos":[4031.167,3431.775],"size":[3.1496,3.5433],"angle":-270,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4031.1669,"y":3431.775},"polygon":[{"x":4032.9387,"y":3430.1998},{"x":4032.9387,"y":3433.3494},{"x":4029.3953,"y":3433.3494},{"x":4029.3953,"y":3430.1998}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"C3","center":[3986,3415.5],"bbox":{"pos":[3986,3415.5],"angle":0,"relpos":[-5.533500004105008,-2.816699999999855],"size":[11.006000008209867,5.612099999999828]},"pads":[{"layers":["F"],"pos":[3988.756,3415.5],"size":[3.1496,3.5433],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3988.7555,"y":3415.5},"polygon":[{"x":3987.1811,"y":3413.7283},{"x":3990.3307,"y":3413.7283},{"x":3990.3307,"y":3417.2717},{"x":3987.1811,"y":3417.2717}],"net":"EN"},{"layers":["F"],"pos":[3983.244,3415.5],"size":[3.1496,3.5433],"angle":0,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3983.2445,"y":3415.5},"polygon":[{"x":3981.6693,"y":3413.7283},{"x":3984.8189,"y":3413.7283},{"x":3984.8189,"y":3417.2717},{"x":3981.6693,"y":3417.2717}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"C4","center":[3986,3386],"bbox":{"pos":[3986,3386],"angle":0,"relpos":[-5.533500004105008,-2.816699999999855],"size":[11.006000008209867,5.612099999999828]},"pads":[{"layers":["F"],"pos":[3988.756,3386],"size":[3.1496,3.5433],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3988.7555,"y":3386},"polygon":[{"x":3987.1811,"y":3384.2283},{"x":3990.3307,"y":3384.2283},{"x":3990.3307,"y":3387.7717},{"x":3987.1811,"y":3387.7717}],"net":"3.3V"},{"layers":["F"],"pos":[3983.244,3386],"size":[3.1496,3.5433],"angle":0,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3983.2445,"y":3386},"polygon":[{"x":3981.6693,"y":3384.2283},{"x":3984.8189,"y":3384.2283},{"x":3984.8189,"y":3387.7717},{"x":3981.6693,"y":3387.7717}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"C5","center":[3986,3393.58],"bbox":{"pos":[3986,3393.58],"angle":0,"relpos":[-5.533500004105008,-2.81670000000031],"size":[11.006000008209867,5.612100000000282]},"pads":[{"layers":["F"],"pos":[3988.756,3393.58],"size":[3.1496,3.5433],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3988.7555,"y":3393.58},"polygon":[{"x":3987.1811,"y":3391.8083},{"x":3990.3307,"y":3391.8083},{"x":3990.3307,"y":3395.3517},{"x":3987.1811,"y":3395.3517}],"net":"3.3V"},{"layers":["F"],"pos":[3983.244,3393.58],"size":[3.1496,3.5433],"angle":0,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3983.2445,"y":3393.58},"polygon":[{"x":3981.6693,"y":3391.8083},{"x":3984.8189,"y":3391.8083},{"x":3984.8189,"y":3395.3517},{"x":3981.6693,"y":3395.3517}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"C6","center":[3970,3393.5],"bbox":{"pos":[3970,3393.5],"angle":0,"relpos":[-7.676750000000084,-3.150000000000091],"size":[15.353500000000167,6.300000000000182]},"pads":[{"layers":["F"],"pos":[3965.276,3393.5],"size":[5.9055,5.35],"angle":0,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3965.2756,"y":3393.5},"polygon":[{"x":3962.3228,"y":3390.825},{"x":3968.2284,"y":3390.825},{"x":3968.2284,"y":3396.175},{"x":3962.3228,"y":3396.175}],"net":"3.3V"},{"layers":["F"],"pos":[3974.724,3393.5],"size":[5.9055,5.35],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3974.7244,"y":3393.5},"polygon":[{"x":3971.7716,"y":3390.825},{"x":3977.6771,"y":3390.825},{"x":3977.6771,"y":3396.175},{"x":3971.7716,"y":3396.175}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"C7","center":[3972.5,3434.5],"bbox":{"pos":[3972.5,3434.5],"angle":270,"relpos":[-12.152149999999892,-6.111800000000585],"size":[24.304299999999785,12.22360000000026]},"pads":[{"layers":["F"],"pos":[3972.5,3441.975],"size":[7.4803,9.3543],"angle":-270,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3972.5,"y":3441.9746},"polygon":[{"x":3977.1771,"y":3438.2348},{"x":3977.1771,"y":3445.7152},{"x":3967.8228,"y":3445.7152},{"x":3967.8228,"y":3438.2348}],"net":"VUSB"},{"layers":["F"],"pos":[3972.5,3427.025],"size":[7.4803,9.3543],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3972.5,"y":3427.0254},"polygon":[{"x":3977.1771,"y":3423.2848},{"x":3977.1771,"y":3430.7652},{"x":3967.8228,"y":3430.7652},{"x":3967.8228,"y":3423.2848}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"R3","center":[3985.97,3408.11],"bbox":{"pos":[3985.97,3408.11],"angle":180,"relpos":[-5.453099999999722,-2.600800000000163],"size":[10.906199999999899,5.201599999999871]},"pads":[{"layers":["F"],"pos":[3983.004,3408.11],"size":[3.1751,3.4016],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3983.0045,"y":3408.11},"polygon":[{"x":3984.592,"y":3406.4092},{"x":3984.592,"y":3409.8108},{"x":3981.4169,"y":3409.8108},{"x":3981.4169,"y":3406.4092}],"net":"3.3V"},{"layers":["F"],"pos":[3988.936,3408.11],"size":[3.1751,3.4016],"angle":-180,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3988.9355,"y":3408.11},"polygon":[{"x":3987.348,"y":3406.4092},{"x":3987.348,"y":3409.8108},{"x":3990.5231,"y":3409.8108},{"x":3990.5231,"y":3406.4092}],"net":"EN"}],"drawings":[],"layer":"F"},{"ref":"R4","center":[4039,3434.5],"bbox":{"pos":[4039,3434.5],"angle":270,"relpos":[-5.453100000000177,-2.6008000000006177],"size":[10.906200000000354,5.201600000000326]},"pads":[{"layers":["F"],"pos":[4039,3437.466],"size":[3.1751,3.4016],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4039,"y":3437.4655},"polygon":[{"x":4037.2992,"y":3435.878},{"x":4040.7008,"y":3435.878},{"x":4040.7008,"y":3439.0531},{"x":4037.2992,"y":3439.0531}],"net":"3.3V"},{"layers":["F"],"pos":[4039,3431.534],"size":[3.1751,3.4016],"angle":-270,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4039,"y":3431.5345},"polygon":[{"x":4037.2992,"y":3433.122},{"x":4040.7008,"y":3433.122},{"x":4040.7008,"y":3429.9469},{"x":4037.2992,"y":3429.9469}],"net":"IO8"}],"drawings":[],"layer":"F"},{"ref":"U3","center":[3969,3408.5],"bbox":{"pos":[3969,3408.5],"angle":90,"relpos":[-11.809749999999894,-9.054999999999836],"size":[20.469900000000507,19.350000000000364]},"pads":[{"layers":["F"],"pos":[3963.09,3403.58],"size":[2.7559,7.4803],"angle":0,"shape":"oval","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3963.09,"y":3403.58},"polygon":[{"x":3963.0556,"y":3407.3198},{"x":3962.987,"y":3407.3163},{"x":3962.9187,"y":3407.3095},{"x":3962.8507,"y":3407.2993},{"x":3962.7834,"y":3407.2857},{"x":3962.7168,"y":3407.2687},{"x":3962.6511,"y":3407.2484},{"x":3962.5866,"y":3407.2249},{"x":3962.5232,"y":3407.1983},{"x":3962.4613,"y":3407.1684},{"x":3962.401,"y":3407.1356},{"x":3962.3424,"y":3407.0998},{"x":3962.2856,"y":3407.0611},{"x":3962.2308,"y":3407.0196},{"x":3962.1782,"y":3406.9754},{"x":3962.1278,"y":3406.9287},{"x":3962.0799,"y":3406.8795},{"x":3962.0344,"y":3406.828},{"x":3961.9916,"y":3406.7742},{"x":3961.9514,"y":3406.7185},{"x":3961.9142,"y":3406.6607},{"x":3961.8798,"y":3406.6012},{"x":3961.8485,"y":3406.5401},{"x":3961.8202,"y":3406.4775},{"x":3961.7951,"y":3406.4135},{"x":3961.7732,"y":3406.3484},{"x":3961.7546,"y":3406.2822},{"x":3961.7393,"y":3406.2152},{"x":3961.7274,"y":3406.1476},{"x":3961.7188,"y":3406.0794},{"x":3961.7137,"y":3406.0109},{"x":3961.712,"y":3405.9422},{"x":3961.712,"y":3401.2178},{"x":3961.7137,"y":3401.1491},{"x":3961.7188,"y":3401.0806},{"x":3961.7274,"y":3401.0124},{"x":3961.7393,"y":3400.9448},{"x":3961.7546,"y":3400.8778},{"x":3961.7732,"y":3400.8116},{"x":3961.7951,"y":3400.7465},{"x":3961.8202,"y":3400.6825},{"x":3961.8485,"y":3400.6199},{"x":3961.8798,"y":3400.5588},{"x":3961.9142,"y":3400.4993},{"x":3961.9514,"y":3400.4415},{"x":3961.9916,"y":3400.3858},{"x":3962.0344,"y":3400.332},{"x":3962.0799,"y":3400.2805},{"x":3962.1278,"y":3400.2313},{"x":3962.1782,"y":3400.1846},{"x":3962.2308,"y":3400.1404},{"x":3962.2856,"y":3400.0989},{"x":3962.3424,"y":3400.0602},{"x":3962.401,"y":3400.0244},{"x":3962.4613,"y":3399.9916},{"x":3962.5232,"y":3399.9617},{"x":3962.5866,"y":3399.9351},{"x":3962.6511,"y":3399.9116},{"x":3962.7168,"y":3399.8913},{"x":3962.7834,"y":3399.8743},{"x":3962.8507,"y":3399.8607},{"x":3962.9187,"y":3399.8505},{"x":3962.987,"y":3399.8437},{"x":3963.0556,"y":3399.8402},{"x":3963.1244,"y":3399.8402},{"x":3963.193,"y":3399.8437},{"x":3963.2613,"y":3399.8505},{"x":3963.3293,"y":3399.8607},{"x":3963.3966,"y":3399.8743},{"x":3963.4632,"y":3399.8913},{"x":3963.5289,"y":3399.9116},{"x":3963.5934,"y":3399.9351},{"x":3963.6568,"y":3399.9617},{"x":3963.7187,"y":3399.9916},{"x":3963.779,"y":3400.0244},{"x":3963.8376,"y":3400.0602},{"x":3963.8944,"y":3400.0989},{"x":3963.9492,"y":3400.1404},{"x":3964.0018,"y":3400.1846},{"x":3964.0522,"y":3400.2313},{"x":3964.1001,"y":3400.2805},{"x":3964.1456,"y":3400.332},{"x":3964.1884,"y":3400.3858},{"x":3964.2286,"y":3400.4415},{"x":3964.2658,"y":3400.4993},{"x":3964.3002,"y":3400.5588},{"x":3964.3315,"y":3400.6199},{"x":3964.3598,"y":3400.6825},{"x":3964.3849,"y":3400.7465},{"x":3964.4068,"y":3400.8116},{"x":3964.4254,"y":3400.8778},{"x":3964.4407,"y":3400.9448},{"x":3964.4526,"y":3401.0124},{"x":3964.4612,"y":3401.0806},{"x":3964.4663,"y":3401.1491},{"x":3964.468,"y":3401.2178},{"x":3964.468,"y":3405.9422},{"x":3964.4663,"y":3406.0109},{"x":3964.4612,"y":3406.0794},{"x":3964.4526,"y":3406.1476},{"x":3964.4407,"y":3406.2152},{"x":3964.4254,"y":3406.2822},{"x":3964.4068,"y":3406.3484},{"x":3964.3849,"y":3406.4135},{"x":3964.3598,"y":3406.4775},{"x":3964.3315,"y":3406.5401},{"x":3964.3002,"y":3406.6012},{"x":3964.2658,"y":3406.6607},{"x":3964.2286,"y":3406.7185},{"x":3964.1884,"y":3406.7742},{"x":3964.1456,"y":3406.828},{"x":3964.1001,"y":3406.8795},{"x":3964.0522,"y":3406.9287},{"x":3964.0018,"y":3406.9754},{"x":3963.9492,"y":3407.0196},{"x":3963.8944,"y":3407.0611},{"x":3963.8376,"y":3407.0998},{"x":3963.779,"y":3407.1356},{"x":3963.7187,"y":3407.1684},{"x":3963.6568,"y":3407.1983},{"x":3963.5934,"y":3407.2249},{"x":3963.5289,"y":3407.2484},{"x":3963.4632,"y":3407.2687},{"x":3963.3966,"y":3407.2857},{"x":3963.3293,"y":3407.2993},{"x":3963.2613,"y":3407.3095},{"x":3963.193,"y":3407.3163},{"x":3963.1244,"y":3407.3198}],"net":"VUSB"},{"layers":["F"],"pos":[3974.91,3403.58],"size":[2.7559,7.4803],"angle":0,"pin1":1,"shape":"oval","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3974.91,"y":3403.58},"polygon":[{"x":3974.8756,"y":3407.3198},{"x":3974.807,"y":3407.3163},{"x":3974.7387,"y":3407.3095},{"x":3974.6707,"y":3407.2993},{"x":3974.6034,"y":3407.2857},{"x":3974.5368,"y":3407.2687},{"x":3974.4711,"y":3407.2484},{"x":3974.4066,"y":3407.2249},{"x":3974.3432,"y":3407.1983},{"x":3974.2813,"y":3407.1684},{"x":3974.221,"y":3407.1356},{"x":3974.1624,"y":3407.0998},{"x":3974.1056,"y":3407.0611},{"x":3974.0508,"y":3407.0196},{"x":3973.9982,"y":3406.9754},{"x":3973.9478,"y":3406.9287},{"x":3973.8999,"y":3406.8795},{"x":3973.8544,"y":3406.828},{"x":3973.8116,"y":3406.7742},{"x":3973.7714,"y":3406.7185},{"x":3973.7342,"y":3406.6607},{"x":3973.6998,"y":3406.6012},{"x":3973.6685,"y":3406.5401},{"x":3973.6402,"y":3406.4775},{"x":3973.6151,"y":3406.4135},{"x":3973.5932,"y":3406.3484},{"x":3973.5746,"y":3406.2822},{"x":3973.5593,"y":3406.2152},{"x":3973.5474,"y":3406.1476},{"x":3973.5388,"y":3406.0794},{"x":3973.5337,"y":3406.0109},{"x":3973.532,"y":3405.9422},{"x":3973.532,"y":3401.2178},{"x":3973.5337,"y":3401.1491},{"x":3973.5388,"y":3401.0806},{"x":3973.5474,"y":3401.0124},{"x":3973.5593,"y":3400.9448},{"x":3973.5746,"y":3400.8778},{"x":3973.5932,"y":3400.8116},{"x":3973.6151,"y":3400.7465},{"x":3973.6402,"y":3400.6825},{"x":3973.6685,"y":3400.6199},{"x":3973.6998,"y":3400.5588},{"x":3973.7342,"y":3400.4993},{"x":3973.7714,"y":3400.4415},{"x":3973.8116,"y":3400.3858},{"x":3973.8544,"y":3400.332},{"x":3973.8999,"y":3400.2805},{"x":3973.9478,"y":3400.2313},{"x":3973.9982,"y":3400.1846},{"x":3974.0508,"y":3400.1404},{"x":3974.1056,"y":3400.0989},{"x":3974.1624,"y":3400.0602},{"x":3974.221,"y":3400.0244},{"x":3974.2813,"y":3399.9916},{"x":3974.3432,"y":3399.9617},{"x":3974.4066,"y":3399.9351},{"x":3974.4711,"y":3399.9116},{"x":3974.5368,"y":3399.8913},{"x":3974.6034,"y":3399.8743},{"x":3974.6707,"y":3399.8607},{"x":3974.7387,"y":3399.8505},{"x":3974.807,"y":3399.8437},{"x":3974.8756,"y":3399.8402},{"x":3974.9444,"y":3399.8402},{"x":3975.013,"y":3399.8437},{"x":3975.0813,"y":3399.8505},{"x":3975.1493,"y":3399.8607},{"x":3975.2166,"y":3399.8743},{"x":3975.2832,"y":3399.8913},{"x":3975.3489,"y":3399.9116},{"x":3975.4134,"y":3399.9351},{"x":3975.4768,"y":3399.9617},{"x":3975.5387,"y":3399.9916},{"x":3975.599,"y":3400.0244},{"x":3975.6576,"y":3400.0602},{"x":3975.7144,"y":3400.0989},{"x":3975.7692,"y":3400.1404},{"x":3975.8218,"y":3400.1846},{"x":3975.8722,"y":3400.2313},{"x":3975.9201,"y":3400.2805},{"x":3975.9656,"y":3400.332},{"x":3976.0084,"y":3400.3858},{"x":3976.0486,"y":3400.4415},{"x":3976.0858,"y":3400.4993},{"x":3976.1202,"y":3400.5588},{"x":3976.1515,"y":3400.6199},{"x":3976.1798,"y":3400.6825},{"x":3976.2049,"y":3400.7465},{"x":3976.2268,"y":3400.8116},{"x":3976.2454,"y":3400.8778},{"x":3976.2607,"y":3400.9448},{"x":3976.2726,"y":3401.0124},{"x":3976.2812,"y":3401.0806},{"x":3976.2863,"y":3401.1491},{"x":3976.288,"y":3401.2178},{"x":3976.288,"y":3405.9422},{"x":3976.2863,"y":3406.0109},{"x":3976.2812,"y":3406.0794},{"x":3976.2726,"y":3406.1476},{"x":3976.2607,"y":3406.2152},{"x":3976.2454,"y":3406.2822},{"x":3976.2268,"y":3406.3484},{"x":3976.2049,"y":3406.4135},{"x":3976.1798,"y":3406.4775},{"x":3976.1515,"y":3406.5401},{"x":3976.1202,"y":3406.6012},{"x":3976.0858,"y":3406.6607},{"x":3976.0486,"y":3406.7185},{"x":3976.0084,"y":3406.7742},{"x":3975.9656,"y":3406.828},{"x":3975.9201,"y":3406.8795},{"x":3975.8722,"y":3406.9287},{"x":3975.8218,"y":3406.9754},{"x":3975.7692,"y":3407.0196},{"x":3975.7144,"y":3407.0611},{"x":3975.6576,"y":3407.0998},{"x":3975.599,"y":3407.1356},{"x":3975.5387,"y":3407.1684},{"x":3975.4768,"y":3407.1983},{"x":3975.4134,"y":3407.2249},{"x":3975.3489,"y":3407.2484},{"x":3975.2832,"y":3407.2687},{"x":3975.2166,"y":3407.2857},{"x":3975.1493,"y":3407.2993},{"x":3975.0813,"y":3407.3095},{"x":3975.013,"y":3407.3163},{"x":3974.9444,"y":3407.3198}],"net":"DGND"},{"layers":["F"],"pos":[3969,3413.42],"size":[7.874,13.7795],"angle":0,"shape":"oval","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3969,"y":3413.42},"polygon":[{"x":3968.9018,"y":3420.3086},{"x":3968.7058,"y":3420.2988},{"x":3968.5105,"y":3420.2792},{"x":3968.3163,"y":3420.25},{"x":3968.1239,"y":3420.2111},{"x":3967.9337,"y":3420.1627},{"x":3967.7461,"y":3420.1048},{"x":3967.5617,"y":3420.0376},{"x":3967.3808,"y":3419.9614},{"x":3967.2039,"y":3419.8762},{"x":3967.0315,"y":3419.7823},{"x":3966.864,"y":3419.68},{"x":3966.7018,"y":3419.5694},{"x":3966.5453,"y":3419.4509},{"x":3966.3949,"y":3419.3247},{"x":3966.251,"y":3419.1912},{"x":3966.114,"y":3419.0506},{"x":3965.9841,"y":3418.9035},{"x":3965.8617,"y":3418.75},{"x":3965.7471,"y":3418.5906},{"x":3965.6406,"y":3418.4257},{"x":3965.5424,"y":3418.2557},{"x":3965.4529,"y":3418.081},{"x":3965.3721,"y":3417.9021},{"x":3965.3004,"y":3417.7193},{"x":3965.2379,"y":3417.5333},{"x":3965.1847,"y":3417.3443},{"x":3965.1411,"y":3417.1529},{"x":3965.107,"y":3416.9596},{"x":3965.0826,"y":3416.7648},{"x":3965.0679,"y":3416.569},{"x":3965.063,"y":3416.3728},{"x":3965.063,"y":3410.4673},{"x":3965.0679,"y":3410.2711},{"x":3965.0826,"y":3410.0753},{"x":3965.107,"y":3409.8805},{"x":3965.1411,"y":3409.6872},{"x":3965.1847,"y":3409.4958},{"x":3965.2379,"y":3409.3068},{"x":3965.3004,"y":3409.1208},{"x":3965.3721,"y":3408.938},{"x":3965.4529,"y":3408.7591},{"x":3965.5424,"y":3408.5844},{"x":3965.6406,"y":3408.4144},{"x":3965.7471,"y":3408.2495},{"x":3965.8617,"y":3408.0901},{"x":3965.9841,"y":3407.9366},{"x":3966.114,"y":3407.7895},{"x":3966.251,"y":3407.6489},{"x":3966.3949,"y":3407.5154},{"x":3966.5453,"y":3407.3892},{"x":3966.7018,"y":3407.2707},{"x":3966.864,"y":3407.1601},{"x":3967.0315,"y":3407.0578},{"x":3967.2039,"y":3406.9639},{"x":3967.3808,"y":3406.8787},{"x":3967.5617,"y":3406.8025},{"x":3967.7461,"y":3406.7353},{"x":3967.9337,"y":3406.6774},{"x":3968.1239,"y":3406.629},{"x":3968.3163,"y":3406.5901},{"x":3968.5105,"y":3406.5609},{"x":3968.7058,"y":3406.5413},{"x":3968.9018,"y":3406.5315},{"x":3969.0982,"y":3406.5315},{"x":3969.2942,"y":3406.5413},{"x":3969.4895,"y":3406.5609},{"x":3969.6837,"y":3406.5901},{"x":3969.8761,"y":3406.629},{"x":3970.0663,"y":3406.6774},{"x":3970.2539,"y":3406.7353},{"x":3970.4383,"y":3406.8025},{"x":3970.6192,"y":3406.8787},{"x":3970.7961,"y":3406.9639},{"x":3970.9685,"y":3407.0578},{"x":3971.136,"y":3407.1601},{"x":3971.2982,"y":3407.2707},{"x":3971.4547,"y":3407.3892},{"x":3971.6051,"y":3407.5154},{"x":3971.749,"y":3407.6489},{"x":3971.886,"y":3407.7895},{"x":3972.0159,"y":3407.9366},{"x":3972.1383,"y":3408.0901},{"x":3972.2529,"y":3408.2495},{"x":3972.3594,"y":3408.4144},{"x":3972.4576,"y":3408.5844},{"x":3972.5471,"y":3408.7591},{"x":3972.6279,"y":3408.938},{"x":3972.6996,"y":3409.1208},{"x":3972.7621,"y":3409.3068},{"x":3972.8153,"y":3409.4958},{"x":3972.8589,"y":3409.6872},{"x":3972.893,"y":3409.8805},{"x":3972.9174,"y":3410.0753},{"x":3972.9321,"y":3410.2711},{"x":3972.937,"y":3410.4673},{"x":3972.937,"y":3416.3728},{"x":3972.9321,"y":3416.569},{"x":3972.9174,"y":3416.7648},{"x":3972.893,"y":3416.9596},{"x":3972.8589,"y":3417.1529},{"x":3972.8153,"y":3417.3443},{"x":3972.7621,"y":3417.5333},{"x":3972.6996,"y":3417.7193},{"x":3972.6279,"y":3417.9021},{"x":3972.5471,"y":3418.081},{"x":3972.4576,"y":3418.2557},{"x":3972.3594,"y":3418.4257},{"x":3972.2529,"y":3418.5906},{"x":3972.1383,"y":3418.75},{"x":3972.0159,"y":3418.9035},{"x":3971.886,"y":3419.0506},{"x":3971.749,"y":3419.1912},{"x":3971.6051,"y":3419.3247},{"x":3971.4547,"y":3419.4509},{"x":3971.2982,"y":3419.5694},{"x":3971.136,"y":3419.68},{"x":3970.9685,"y":3419.7823},{"x":3970.7961,"y":3419.8762},{"x":3970.6192,"y":3419.9614},{"x":3970.4383,"y":3420.0376},{"x":3970.2539,"y":3420.1048},{"x":3970.0663,"y":3420.1627},{"x":3969.8761,"y":3420.2111},{"x":3969.6837,"y":3420.25},{"x":3969.4895,"y":3420.2792},{"x":3969.2942,"y":3420.2988},{"x":3969.0982,"y":3420.3086}],"net":"3.3V"},{"layers":["F"],"pos":[3969,3403.97],"size":[8.2677,2.7559],"angle":-90,"shape":"oval","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3969,"y":3403.97},"polygon":[{"x":3968.9656,"y":3408.1035},{"x":3968.897,"y":3408.1},{"x":3968.8287,"y":3408.0932},{"x":3968.7607,"y":3408.083},{"x":3968.6934,"y":3408.0694},{"x":3968.6268,"y":3408.0524},{"x":3968.5611,"y":3408.0321},{"x":3968.4966,"y":3408.0086},{"x":3968.4332,"y":3407.982},{"x":3968.3713,"y":3407.9521},{"x":3968.311,"y":3407.9193},{"x":3968.2524,"y":3407.8835},{"x":3968.1956,"y":3407.8448},{"x":3968.1408,"y":3407.8033},{"x":3968.0882,"y":3407.7591},{"x":3968.0378,"y":3407.7124},{"x":3967.9899,"y":3407.6632},{"x":3967.9444,"y":3407.6117},{"x":3967.9016,"y":3407.5579},{"x":3967.8614,"y":3407.5022},{"x":3967.8242,"y":3407.4444},{"x":3967.7898,"y":3407.3849},{"x":3967.7585,"y":3407.3238},{"x":3967.7302,"y":3407.2612},{"x":3967.7051,"y":3407.1972},{"x":3967.6832,"y":3407.1321},{"x":3967.6646,"y":3407.0659},{"x":3967.6493,"y":3406.9989},{"x":3967.6374,"y":3406.9313},{"x":3967.6288,"y":3406.8631},{"x":3967.6237,"y":3406.7946},{"x":3967.622,"y":3406.7259},{"x":3967.622,"y":3401.2141},{"x":3967.6237,"y":3401.1454},{"x":3967.6288,"y":3401.0769},{"x":3967.6374,"y":3401.0087},{"x":3967.6493,"y":3400.9411},{"x":3967.6646,"y":3400.8741},{"x":3967.6832,"y":3400.8079},{"x":3967.7051,"y":3400.7428},{"x":3967.7302,"y":3400.6788},{"x":3967.7585,"y":3400.6162},{"x":3967.7898,"y":3400.5551},{"x":3967.8242,"y":3400.4956},{"x":3967.8614,"y":3400.4378},{"x":3967.9016,"y":3400.3821},{"x":3967.9444,"y":3400.3283},{"x":3967.9899,"y":3400.2768},{"x":3968.0378,"y":3400.2276},{"x":3968.0882,"y":3400.1809},{"x":3968.1408,"y":3400.1367},{"x":3968.1956,"y":3400.0952},{"x":3968.2524,"y":3400.0565},{"x":3968.311,"y":3400.0207},{"x":3968.3713,"y":3399.9879},{"x":3968.4332,"y":3399.958},{"x":3968.4966,"y":3399.9314},{"x":3968.5611,"y":3399.9079},{"x":3968.6268,"y":3399.8876},{"x":3968.6934,"y":3399.8706},{"x":3968.7607,"y":3399.857},{"x":3968.8287,"y":3399.8468},{"x":3968.897,"y":3399.84},{"x":3968.9656,"y":3399.8365},{"x":3969.0344,"y":3399.8365},{"x":3969.103,"y":3399.84},{"x":3969.1713,"y":3399.8468},{"x":3969.2393,"y":3399.857},{"x":3969.3066,"y":3399.8706},{"x":3969.3732,"y":3399.8876},{"x":3969.4389,"y":3399.9079},{"x":3969.5034,"y":3399.9314},{"x":3969.5668,"y":3399.958},{"x":3969.6287,"y":3399.9879},{"x":3969.689,"y":3400.0207},{"x":3969.7476,"y":3400.0565},{"x":3969.8044,"y":3400.0952},{"x":3969.8592,"y":3400.1367},{"x":3969.9118,"y":3400.1809},{"x":3969.9622,"y":3400.2276},{"x":3970.0101,"y":3400.2768},{"x":3970.0556,"y":3400.3283},{"x":3970.0984,"y":3400.3821},{"x":3970.1386,"y":3400.4378},{"x":3970.1758,"y":3400.4956},{"x":3970.2102,"y":3400.5551},{"x":3970.2415,"y":3400.6162},{"x":3970.2698,"y":3400.6788},{"x":3970.2949,"y":3400.7428},{"x":3970.3168,"y":3400.8079},{"x":3970.3354,"y":3400.8741},{"x":3970.3507,"y":3400.9411},{"x":3970.3626,"y":3401.0087},{"x":3970.3712,"y":3401.0769},{"x":3970.3763,"y":3401.1454},{"x":3970.378,"y":3401.2141},{"x":3970.378,"y":3406.7259},{"x":3970.3763,"y":3406.7946},{"x":3970.3712,"y":3406.8631},{"x":3970.3626,"y":3406.9313},{"x":3970.3507,"y":3406.9989},{"x":3970.3354,"y":3407.0659},{"x":3970.3168,"y":3407.1321},{"x":3970.2949,"y":3407.1972},{"x":3970.2698,"y":3407.2612},{"x":3970.2415,"y":3407.3238},{"x":3970.2102,"y":3407.3849},{"x":3970.1758,"y":3407.4444},{"x":3970.1386,"y":3407.5022},{"x":3970.0984,"y":3407.5579},{"x":3970.0556,"y":3407.6117},{"x":3970.0101,"y":3407.6632},{"x":3969.9622,"y":3407.7124},{"x":3969.9118,"y":3407.7591},{"x":3969.8592,"y":3407.8033},{"x":3969.8044,"y":3407.8448},{"x":3969.7476,"y":3407.8835},{"x":3969.689,"y":3407.9193},{"x":3969.6287,"y":3407.9521},{"x":3969.5668,"y":3407.982},{"x":3969.5034,"y":3408.0086},{"x":3969.4389,"y":3408.0321},{"x":3969.3732,"y":3408.0524},{"x":3969.3066,"y":3408.0694},{"x":3969.2393,"y":3408.083},{"x":3969.1713,"y":3408.0932},{"x":3969.103,"y":3408.1},{"x":3969.0344,"y":3408.1035}],"net":"3.3V"}],"drawings":[],"layer":"F"},{"ref":"Q1","center":[4003.9139,3434.5],"bbox":{"pos":[4003.9139,3434.5],"angle":180,"relpos":[-6.397749999999633,-6.008699999999408],"size":[12.795300000000225,12.017399999999725]},"pads":[{"layers":["F"],"pos":[3999.977,3430.76],"size":[4.9213,2.7559],"angle":-180,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3999.9771,"y":3430.7598},"polygon":[{"x":4002.4375,"y":3432.138},{"x":3997.5163,"y":3432.138},{"x":3997.5163,"y":3429.382},{"x":4002.4375,"y":3429.382}],"net":"R2_1"},{"layers":["F"],"pos":[3999.977,3438.24],"size":[4.9213,2.7559],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3999.9771,"y":3438.2402},"polygon":[{"x":4002.4375,"y":3439.6179},{"x":3997.5163,"y":3439.6179},{"x":3997.5163,"y":3436.862},{"x":4002.4375,"y":3436.862}],"net":"DGND"},{"layers":["F"],"pos":[4007.851,3434.5],"size":[4.9213,2.7559],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4007.8507,"y":3434.5},"polygon":[{"x":4010.3115,"y":3435.8779},{"x":4005.3903,"y":3435.8779},{"x":4005.3903,"y":3433.122},{"x":4010.3115,"y":3433.122}],"net":"Q1_3"}],"drawings":[],"layer":"F"},{"ref":"U1","center":[4020,3400.5],"bbox":{"pos":[4020,3400.5],"angle":0,"relpos":[-27.95300000000043,-43.30729999999994],"size":[53.93740000000025,65.35449999999992]},"pads":[{"layers":["F"],"pos":[3996.772,3384.752],"size":[1.5748,3.1496],"angle":-90,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3384.752},"polygon":[{"x":3995.1969,"y":3385.5394},{"x":3995.1969,"y":3383.9646},{"x":3998.3465,"y":3383.9646},{"x":3998.3465,"y":3385.5394}],"net":"DGND"},{"layers":["F"],"pos":[3996.772,3387.902],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3387.9016},"polygon":[{"x":3995.1969,"y":3388.689},{"x":3995.1969,"y":3387.1142},{"x":3998.3465,"y":3387.1142},{"x":3998.3465,"y":3388.689}],"net":"DGND"},{"layers":["F"],"pos":[3996.772,3391.051],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3391.0512},"polygon":[{"x":3995.1969,"y":3391.8386},{"x":3995.1969,"y":3390.2638},{"x":3998.3465,"y":3390.2638},{"x":3998.3465,"y":3391.8386}],"net":"3.3V"},{"layers":["F"],"pos":[3996.772,3394.201],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3394.2008},"polygon":[{"x":3995.1969,"y":3394.9882},{"x":3995.1969,"y":3393.4134},{"x":3998.3465,"y":3393.4134},{"x":3998.3465,"y":3394.9882}],"net":""},{"layers":["F"],"pos":[3996.772,3397.35],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3397.3504},"polygon":[{"x":3995.1969,"y":3398.1378},{"x":3995.1969,"y":3396.563},{"x":3998.3465,"y":3396.563},{"x":3998.3465,"y":3398.1378}],"net":"IO2"},{"layers":["F"],"pos":[3996.772,3400.5],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3400.5},"polygon":[{"x":3995.1969,"y":3401.2874},{"x":3995.1969,"y":3399.7126},{"x":3998.3465,"y":3399.7126},{"x":3998.3465,"y":3401.2874}],"net":"IO3"},{"layers":["F"],"pos":[3996.772,3403.65],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3403.6496},"polygon":[{"x":3995.1969,"y":3404.437},{"x":3995.1969,"y":3402.8622},{"x":3998.3465,"y":3402.8622},{"x":3998.3465,"y":3404.437}],"net":""},{"layers":["F"],"pos":[3996.772,3406.799],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3406.7992},"polygon":[{"x":3995.1969,"y":3407.5866},{"x":3995.1969,"y":3406.0118},{"x":3998.3465,"y":3406.0118},{"x":3998.3465,"y":3407.5866}],"net":"EN"},{"layers":["F"],"pos":[3996.772,3409.949],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3409.9488},"polygon":[{"x":3995.1969,"y":3410.7362},{"x":3995.1969,"y":3409.1614},{"x":3998.3465,"y":3409.1614},{"x":3998.3465,"y":3410.7362}],"net":""},{"layers":["F"],"pos":[3996.772,3413.098],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3413.0984},"polygon":[{"x":3995.1969,"y":3413.8858},{"x":3995.1969,"y":3412.311},{"x":3998.3465,"y":3412.311},{"x":3998.3465,"y":3413.8858}],"net":""},{"layers":["F"],"pos":[3996.772,3416.248],"size":[1.5748,3.1496],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.7717,"y":3416.248},"polygon":[{"x":3995.1969,"y":3417.0354},{"x":3995.1969,"y":3415.4606},{"x":3998.3465,"y":3415.4606},{"x":3998.3465,"y":3417.0354}],"net":"DGND"},{"layers":["F"],"pos":[4001.102,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4001.1024,"y":3419.7913},"polygon":[{"x":4001.8898,"y":3421.3661},{"x":4000.315,"y":3421.3661},{"x":4000.315,"y":3418.2165},{"x":4001.8898,"y":3418.2165}],"net":"IO0"},{"layers":["F"],"pos":[4004.252,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4004.252,"y":3419.7913},"polygon":[{"x":4005.0394,"y":3421.3661},{"x":4003.4646,"y":3421.3661},{"x":4003.4646,"y":3418.2165},{"x":4005.0394,"y":3418.2165}],"net":"BLK"},{"layers":["F"],"pos":[4007.402,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4007.4016,"y":3419.7913},"polygon":[{"x":4008.189,"y":3421.3661},{"x":4006.6142,"y":3421.3661},{"x":4006.6142,"y":3418.2165},{"x":4008.189,"y":3418.2165}],"net":"DGND"},{"layers":["F"],"pos":[4010.551,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4010.5512,"y":3419.7913},"polygon":[{"x":4011.3386,"y":3421.3661},{"x":4009.7638,"y":3421.3661},{"x":4009.7638,"y":3418.2165},{"x":4011.3386,"y":3418.2165}],"net":""},{"layers":["F"],"pos":[4013.701,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4013.7008,"y":3419.7913},"polygon":[{"x":4014.4882,"y":3421.3661},{"x":4012.9134,"y":3421.3661},{"x":4012.9134,"y":3418.2165},{"x":4014.4882,"y":3418.2165}],"net":"HCS"},{"layers":["F"],"pos":[4016.85,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4016.8504,"y":3419.7913},"polygon":[{"x":4017.6378,"y":3421.3661},{"x":4016.063,"y":3421.3661},{"x":4016.063,"y":3418.2165},{"x":4017.6378,"y":3418.2165}],"net":""},{"layers":["F"],"pos":[4020,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4020,"y":3419.7913},"polygon":[{"x":4020.7874,"y":3421.3661},{"x":4019.2126,"y":3421.3661},{"x":4019.2126,"y":3418.2165},{"x":4020.7874,"y":3418.2165}],"net":"REST"},{"layers":["F"],"pos":[4023.15,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4023.1496,"y":3419.7913},"polygon":[{"x":4023.937,"y":3421.3661},{"x":4022.3622,"y":3421.3661},{"x":4022.3622,"y":3418.2165},{"x":4023.937,"y":3418.2165}],"net":"DC"},{"layers":["F"],"pos":[4026.299,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4026.2992,"y":3419.7913},"polygon":[{"x":4027.0866,"y":3421.3661},{"x":4025.5118,"y":3421.3661},{"x":4025.5118,"y":3418.2165},{"x":4027.0866,"y":3418.2165}],"net":"HCLK"},{"layers":["F"],"pos":[4029.449,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4029.4488,"y":3419.7913},"polygon":[{"x":4030.2362,"y":3421.3661},{"x":4028.6614,"y":3421.3661},{"x":4028.6614,"y":3418.2165},{"x":4030.2362,"y":3418.2165}],"net":"HMOSI"},{"layers":["F"],"pos":[4032.598,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4032.5984,"y":3419.7913},"polygon":[{"x":4033.3858,"y":3421.3661},{"x":4031.811,"y":3421.3661},{"x":4031.811,"y":3418.2165},{"x":4033.3858,"y":3418.2165}],"net":"IO8"},{"layers":["F"],"pos":[4035.748,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4035.748,"y":3419.7913},"polygon":[{"x":4036.5354,"y":3421.3661},{"x":4034.9606,"y":3421.3661},{"x":4034.9606,"y":3418.2165},{"x":4036.5354,"y":3418.2165}],"net":"IO9"},{"layers":["F"],"pos":[4038.898,3419.791],"size":[1.5748,3.1496],"angle":-180,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4038.8976,"y":3419.7913},"polygon":[{"x":4039.685,"y":3421.3661},{"x":4038.1102,"y":3421.3661},{"x":4038.1102,"y":3418.2165},{"x":4039.685,"y":3418.2165}],"net":""},{"layers":["F"],"pos":[4043.228,3416.248],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3416.248},"polygon":[{"x":4044.8031,"y":3415.4606},{"x":4044.8031,"y":3417.0354},{"x":4041.6535,"y":3417.0354},{"x":4041.6535,"y":3415.4606}],"net":""},{"layers":["F"],"pos":[4043.228,3413.098],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3413.0984},"polygon":[{"x":4044.8031,"y":3412.311},{"x":4044.8031,"y":3413.8858},{"x":4041.6535,"y":3413.8858},{"x":4041.6535,"y":3412.311}],"net":"USB_D-"},{"layers":["F"],"pos":[4043.228,3409.949],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3409.9488},"polygon":[{"x":4044.8031,"y":3409.1614},{"x":4044.8031,"y":3410.7362},{"x":4041.6535,"y":3410.7362},{"x":4041.6535,"y":3409.1614}],"net":"USB_D+"},{"layers":["F"],"pos":[4043.228,3406.799],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3406.7992},"polygon":[{"x":4044.8031,"y":3406.0118},{"x":4044.8031,"y":3407.5866},{"x":4041.6535,"y":3407.5866},{"x":4041.6535,"y":3406.0118}],"net":""},{"layers":["F"],"pos":[4043.228,3403.65],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3403.6496},"polygon":[{"x":4044.8031,"y":3402.8622},{"x":4044.8031,"y":3404.437},{"x":4041.6535,"y":3404.437},{"x":4041.6535,"y":3402.8622}],"net":""},{"layers":["F"],"pos":[4043.228,3400.5],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3400.5},"polygon":[{"x":4044.8031,"y":3399.7126},{"x":4044.8031,"y":3401.2874},{"x":4041.6535,"y":3401.2874},{"x":4041.6535,"y":3399.7126}],"net":"CAN_RX"},{"layers":["F"],"pos":[4043.228,3397.35],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3397.3504},"polygon":[{"x":4044.8031,"y":3396.563},{"x":4044.8031,"y":3398.1378},{"x":4041.6535,"y":3398.1378},{"x":4041.6535,"y":3396.563}],"net":"CAN_TX"},{"layers":["F"],"pos":[4043.228,3394.201],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3394.2008},"polygon":[{"x":4044.8031,"y":3393.4134},{"x":4044.8031,"y":3394.9882},{"x":4041.6535,"y":3394.9882},{"x":4041.6535,"y":3393.4134}],"net":""},{"layers":["F"],"pos":[4043.228,3391.051],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3391.0512},"polygon":[{"x":4044.8031,"y":3390.2638},{"x":4044.8031,"y":3391.8386},{"x":4041.6535,"y":3391.8386},{"x":4041.6535,"y":3390.2638}],"net":""},{"layers":["F"],"pos":[4043.228,3387.902],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3387.9016},"polygon":[{"x":4044.8031,"y":3387.1142},{"x":4044.8031,"y":3388.689},{"x":4041.6535,"y":3388.689},{"x":4041.6535,"y":3387.1142}],"net":""},{"layers":["F"],"pos":[4043.228,3384.752],"size":[1.5748,3.1496],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.2283,"y":3384.752},"polygon":[{"x":4044.8031,"y":3383.9646},{"x":4044.8031,"y":3385.5394},{"x":4041.6535,"y":3385.5394},{"x":4041.6535,"y":3383.9646}],"net":""},{"layers":["F"],"pos":[4038.898,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4038.8976,"y":3381.2087},"polygon":[{"x":4038.1102,"y":3379.6339},{"x":4039.685,"y":3379.6339},{"x":4039.685,"y":3382.7835},{"x":4038.1102,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4035.748,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4035.748,"y":3381.2087},"polygon":[{"x":4034.9606,"y":3379.6339},{"x":4036.5354,"y":3379.6339},{"x":4036.5354,"y":3382.7835},{"x":4034.9606,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4032.598,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4032.5984,"y":3381.2087},"polygon":[{"x":4031.811,"y":3379.6339},{"x":4033.3858,"y":3379.6339},{"x":4033.3858,"y":3382.7835},{"x":4031.811,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4029.449,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4029.4488,"y":3381.2087},"polygon":[{"x":4028.6614,"y":3379.6339},{"x":4030.2362,"y":3379.6339},{"x":4030.2362,"y":3382.7835},{"x":4028.6614,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4026.299,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4026.2992,"y":3381.2087},"polygon":[{"x":4025.5118,"y":3379.6339},{"x":4027.0866,"y":3379.6339},{"x":4027.0866,"y":3382.7835},{"x":4025.5118,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4023.15,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4023.1496,"y":3381.2087},"polygon":[{"x":4022.3622,"y":3379.6339},{"x":4023.937,"y":3379.6339},{"x":4023.937,"y":3382.7835},{"x":4022.3622,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4020,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4020,"y":3381.2087},"polygon":[{"x":4019.2126,"y":3379.6339},{"x":4020.7874,"y":3379.6339},{"x":4020.7874,"y":3382.7835},{"x":4019.2126,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4016.85,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4016.8504,"y":3381.2087},"polygon":[{"x":4016.063,"y":3379.6339},{"x":4017.6378,"y":3379.6339},{"x":4017.6378,"y":3382.7835},{"x":4016.063,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4013.701,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4013.7008,"y":3381.2087},"polygon":[{"x":4012.9134,"y":3379.6339},{"x":4014.4882,"y":3379.6339},{"x":4014.4882,"y":3382.7835},{"x":4012.9134,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4010.551,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4010.5512,"y":3381.2087},"polygon":[{"x":4009.7638,"y":3379.6339},{"x":4011.3386,"y":3379.6339},{"x":4011.3386,"y":3382.7835},{"x":4009.7638,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4007.402,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4007.4016,"y":3381.2087},"polygon":[{"x":4006.6142,"y":3379.6339},{"x":4008.189,"y":3379.6339},{"x":4008.189,"y":3382.7835},{"x":4006.6142,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4004.252,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4004.252,"y":3381.2087},"polygon":[{"x":4003.4646,"y":3379.6339},{"x":4005.0394,"y":3379.6339},{"x":4005.0394,"y":3382.7835},{"x":4003.4646,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4001.102,3381.209],"size":[1.5748,3.1496],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4001.1024,"y":3381.2087},"polygon":[{"x":4000.315,"y":3379.6339},{"x":4001.8898,"y":3379.6339},{"x":4001.8898,"y":3382.7835},{"x":4000.315,"y":3382.7835}],"net":"DGND"},{"layers":["F"],"pos":[4043.425,3381.012],"size":[2.7559,2.7559],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.4252,"y":3381.0118},"polygon":[{"x":4042.0472,"y":3379.6338},{"x":4044.8032,"y":3379.6338},{"x":4044.8032,"y":3382.3898},{"x":4042.0472,"y":3382.3898}],"net":"DGND"},{"layers":["F"],"pos":[4043.425,3419.988],"size":[2.7559,2.7559],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4043.4252,"y":3419.9882},"polygon":[{"x":4042.0472,"y":3418.6102},{"x":4044.8032,"y":3418.6102},{"x":4044.8032,"y":3421.3662},{"x":4042.0472,"y":3421.3662}],"net":"DGND"},{"layers":["F"],"pos":[3996.575,3419.988],"size":[2.7559,2.7559],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.5748,"y":3419.9882},"polygon":[{"x":3995.1968,"y":3418.6102},{"x":3997.9528,"y":3418.6102},{"x":3997.9528,"y":3421.3662},{"x":3995.1968,"y":3421.3662}],"net":"DGND"},{"layers":["F"],"pos":[3996.575,3381.012],"size":[2.7559,2.7559],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3996.5748,"y":3381.0118},"polygon":[{"x":3995.1968,"y":3379.6338},{"x":3997.9528,"y":3379.6338},{"x":3997.9528,"y":3382.3898},{"x":3995.1968,"y":3382.3898}],"net":"DGND"},{"layers":["F"],"pos":[4012.224,3392.724],"size":[5.7087,5.7087],"angle":0,"shape":"polygon","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4012.2238,"y":3392.7245},"polygon":[{"x":4009.3696,"y":3392.2325},{"x":4011.7318,"y":3389.8703},{"x":4015.0782,"y":3389.8703},{"x":4015.0782,"y":3395.5789},{"x":4009.3696,"y":3395.5789}],"net":"DGND"},{"layers":["F"],"pos":[4027.775,3408.276],"size":[5.7087,5.7087],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4027.7752,"y":3408.2759},"polygon":[{"x":4024.9208,"y":3405.4215},{"x":4030.6294,"y":3405.4215},{"x":4030.6294,"y":3411.1301},{"x":4024.9208,"y":3411.1301}],"net":"DGND"},{"layers":["F"],"pos":[4020,3408.276],"size":[5.7087,5.7087],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4019.9995,"y":3408.2759},"polygon":[{"x":4017.1452,"y":3405.4215},{"x":4022.8538,"y":3405.4215},{"x":4022.8538,"y":3411.1301},{"x":4017.1452,"y":3411.1301}],"net":"DGND"},{"layers":["F"],"pos":[4012.224,3408.276],"size":[5.7087,5.7087],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4012.2238,"y":3408.2759},"polygon":[{"x":4009.3696,"y":3405.4215},{"x":4015.0782,"y":3405.4215},{"x":4015.0782,"y":3411.1301},{"x":4009.3696,"y":3411.1301}],"net":"DGND"},{"layers":["F"],"pos":[4012.224,3400.5],"size":[5.7087,5.7087],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4012.2238,"y":3400.5002},"polygon":[{"x":4009.3696,"y":3397.6459},{"x":4015.0782,"y":3397.6459},{"x":4015.0782,"y":3403.3545},{"x":4009.3696,"y":3403.3545}],"net":"DGND"},{"layers":["F"],"pos":[4020,3392.725],"size":[5.7087,5.7087],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4019.9995,"y":3392.7245},"polygon":[{"x":4017.1452,"y":3389.8703},{"x":4022.8538,"y":3389.8703},{"x":4022.8538,"y":3395.5789},{"x":4017.1452,"y":3395.5789}],"net":"DGND"},{"layers":["F"],"pos":[4027.775,3392.725],"size":[5.7087,5.7087],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4027.7752,"y":3392.7245},"polygon":[{"x":4024.9208,"y":3389.8703},{"x":4030.6294,"y":3389.8703},{"x":4030.6294,"y":3395.5789},{"x":4024.9208,"y":3395.5789}],"net":"DGND"},{"layers":["F"],"pos":[4027.775,3400.5],"size":[5.7087,5.7087],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4027.7752,"y":3400.5002},"polygon":[{"x":4024.9208,"y":3397.6459},{"x":4030.6294,"y":3397.6459},{"x":4030.6294,"y":3403.3545},{"x":4024.9208,"y":3403.3545}],"net":"DGND"},{"layers":["F"],"pos":[4020,3400.5],"size":[5.7087,5.7087],"angle":0,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4019.9995,"y":3400.5002},"polygon":[{"x":4017.1452,"y":3397.6459},{"x":4022.8538,"y":3397.6459},{"x":4022.8538,"y":3403.3545},{"x":4017.1452,"y":3403.3545}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"C1","center":[4023.1393,3434.5305],"bbox":{"pos":[4023.1393,3434.5305],"angle":270,"relpos":[-5.533500004105008,-2.8167000000007647],"size":[11.006000008210776,5.612100000000282]},"pads":[{"layers":["F"],"pos":[4023.139,3437.286],"size":[3.1496,3.5433],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4023.1393,"y":3437.286},"polygon":[{"x":4024.911,"y":3435.7116},{"x":4024.911,"y":3438.8612},{"x":4021.3676,"y":3438.8612},{"x":4021.3676,"y":3435.7116}],"net":"3.3V"},{"layers":["F"],"pos":[4023.139,3431.775],"size":[3.1496,3.5433],"angle":-270,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4023.1393,"y":3431.775},"polygon":[{"x":4024.911,"y":3430.1998},{"x":4024.911,"y":3433.3494},{"x":4021.3676,"y":3433.3494},{"x":4021.3676,"y":3430.1998}],"net":"DGND"}],"drawings":[],"layer":"F"},{"ref":"R1","center":[4015.3277,3434.5],"bbox":{"pos":[4015.3277,3434.5],"angle":270,"relpos":[-5.453100000000177,-2.6008000000006177],"size":[10.906200000000354,5.201599999999871]},"pads":[{"layers":["F"],"pos":[4015.328,3437.466],"size":[3.1751,3.4016],"angle":-270,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4015.3277,"y":3437.4655},"polygon":[{"x":4013.6269,"y":3435.878},{"x":4017.0285,"y":3435.878},{"x":4017.0285,"y":3439.0531},{"x":4013.6269,"y":3439.0531}],"net":"LED_K"},{"layers":["F"],"pos":[4015.328,3431.534],"size":[3.1751,3.4016],"angle":-270,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":4015.3277,"y":3431.5345},"polygon":[{"x":4013.6269,"y":3433.122},{"x":4017.0285,"y":3433.122},{"x":4017.0285,"y":3429.9469},{"x":4013.6269,"y":3429.9469}],"net":"Q1_3"}],"drawings":[],"layer":"F"},{"ref":"R2","center":[3992.5,3434.5],"bbox":{"pos":[3992.5,3434.5],"angle":90,"relpos":[-5.453099999999722,-2.600800000000163],"size":[10.906200000000354,5.201600000000326]},"pads":[{"layers":["F"],"pos":[3992.5,3431.534],"size":[3.1751,3.4016],"angle":-90,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3992.5,"y":3431.5345},"polygon":[{"x":3994.2008,"y":3433.122},{"x":3990.7992,"y":3433.122},{"x":3990.7992,"y":3429.9469},{"x":3994.2008,"y":3429.9469}],"net":"BLK"},{"layers":["F"],"pos":[3992.5,3437.466],"size":[3.1751,3.4016],"angle":-90,"pin1":1,"shape":"rect","type":"smd","drillsize":[0,0],"holeCenterPoint":{"x":3992.5,"y":3437.4655},"polygon":[{"x":3994.2008,"y":3435.878},{"x":3990.7992,"y":3435.878},{"x":3990.7992,"y":3439.0531},{"x":3994.2008,"y":3439.0531}],"net":"R2_1"}],"drawings":[],"layer":"F"}],"metadata":{"title":"lcd_1.28_mini","revision":"0","company":"Unknown Company","date":"2024-03-26"},"tracks":{"F":[{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4043.43,3419.99 4048.5,3420"},{"type":"polyline","net":"IO9","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4055.118,3392.831 4051.209,3392.831 4051.04,3393"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4023.139,3437.286 4023.139,3441.361 4017,3447.5"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4013,3447.5 4017,3447.5"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4045,3427.5 4045,3430.5339"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4039,3437.466 4041.034,3437.466 4045,3433.5 4045,3430.534"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3965.28,3393.5 3965.28,3388.4629"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3965.28,3388.4629 3965.28,3386.72 3971,3381 3988,3381 3988.76,3381.76 3988.76,3386"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4020,3392.725 4020,3381.209"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4020,3392.725 4012.225,3392.725"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4020,3400.5 4027.775,3400.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4020,3400.5 4012.224,3400.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4012.224,3392.724 4012.224,3400.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4012.224,3400.5 4012.224,3408.276"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4027.775,3392.725 4020,3392.725"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4027.775,3408.276 4027.775,3400.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4027.775,3400.5 4027.775,3392.725"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4012.224,3408.276 4020,3408.276"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4020,3408.276 4027.775,3408.276"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3996.772,3416.248 4007.402,3416.248"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4007.402,3419.791 4007.402,3412.598 4011.724,3408.276 4012.224,3408.276"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4007.4,3419.79 4007.4,3423.4 4010.5,3426.5 4017.5,3426.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3978,3386 3974.5,3386"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3983.244,3386 3978,3386"},{"type":"polyline","net":"IO0","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3981.016,3448.921 3983.079,3448.921 3988.5,3443.5 3988.5,3427.5 3990.5,3425.5 3999.5,3425.5 4001.102,3423.898 4001.102,3419.791"},{"type":"polyline","net":"BLK","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3992.5,3431.53 3992.5,3429.5 3994.5,3427.5 4002.5,3427.5 4004.25,3425.75 4004.25,3419.79"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4023.139,3431.775 4022.775,3431.775 4017.5,3426.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3999.9771,3438.24 4000,3438.2629 4000,3451.5"},{"type":"polyline","net":"LED_K","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4007.5,3447.5 4007.5,3444 4014.034,3437.466 4015.328,3437.466"},{"type":"polyline","net":"IO8","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4039,3431.534 4039,3429.5 4032.598,3423.098 4032.598,3419.791"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4031.5,3431.5001 4023.4723,3431.5001"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4031,3437.4999 4022.9723,3437.4999"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4039,3437.5 4039,3437.5 4031.17,3437.5 4031,3437.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3996.772,3387.902 3996.575,3387.705 3996.575,3381.012"},{"type":"polyline","net":"USB_D-","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4043.228,3413.098 4045.8031,3413.098 4046.5784,3412.3227 4050.5784,3412.3227 4051.9714,3412.3227 4052.4051,3412.7564 4052.4051,3431.3344 4046.4016,3437.3379 4037.838,3445.9016 4033,3445.9016 4024.3832,3445.9016 4019.2008,3451.084 4019.2008,3455.7461 4016.5,3458.4469 4016.5,3461.034"},{"type":"polyline","net":"USB_D+","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4043.228,3409.949 4045.8031,3409.949 4046.5784,3410.7243 4050.5784,3410.7243 4052.6335,3410.7243 4054.0035,3412.0944 4054.0035,3431.9965 4048,3438 4038.5001,3447.5 4033,3447.5 4025.0453,3447.5 4020.7992,3451.7461 4020.7992,3455.7461 4023.5,3458.4469 4023.5,3461.034"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3983.244,3386 3983.244,3393.5802"},{"type":"polyline","net":"LED3_4","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4064.08,3454.02 4066,3452 4066,3448 4056.5,3438.5 4051.5,3438.5 4038.5,3451.5 4038.5,3462.5 4037,3464 3985.91,3464 3978.98,3457.08"},{"type":"polyline","net":"VUSB","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4005,3477.61 4005,3485 4006.5,3486.5 4040,3486.5 4041.5,3485 4041.5,3451.5 4050.5,3442.5 4053.4,3442.5 4054.95,3444.05"},{"type":"polyline","net":"U4_3","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4023.5,3466.966 4023.5,3476.11 4025,3477.61"},{"type":"polyline","net":"U4_2","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4015,3477.61 4016.5,3476.11 4016.5,3466.966"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3972.5,3427.02 3972.5,3425.5 3974.91,3422.91 3974.91,3403.58"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3974.91,3403.58 3974.724,3403.394 3974.724,3393.5"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3969,3403.97 3969,3399 3965.276,3395.276 3965.276,3393.5"},{"type":"polyline","net":"R2_1","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3992.5,3437.466 3993.034,3437.466 3999.74,3430.76 3999.9774,3430.76"},{"type":"polyline","net":"Q1_3","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4007.851,3434.5 4007.851,3432.15 4008.531,3431.53 4015.331,3431.53"},{"type":"polyline","net":"DC","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4021,3425.5 4021,3424 4023.1499,3421.8501 4023.1499,3419.791"},{"type":"polyline","net":"REST","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4032,3415.5 4020.5,3415.5 4020,3416 4020,3419.791"},{"type":"polyline","net":"HCS","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4013.7009,3419.791 4013.7009,3416.2991 4014,3416"},{"type":"polyline","net":"HCLK","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4026.2991,3419.791 4026.2991,3425.2991 4026.5,3425.5"},{"type":"polyline","net":"HMOSI","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4029.45,3419.79 4029.5,3425"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4038.898,3381.209 4039.095,3381.012 4043.425,3381.012"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3996.772,3416.248 3996.575,3416.445 3996.575,3419.988"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3996.575,3419.988 3983.988,3419.988 3983.244,3419.244 3983.244,3415.5"},{"type":"polyline","net":"EN","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3988.756,3415.5 3988.966,3415.29 3988.966,3408"},{"type":"polyline","net":"EN","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3988.966,3408 3990.5,3408 3991.701,3406.799 3996.772,3406.799"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4001.102,3381.209 4038.898,3381.209"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3988.756,3393.5802 3988.756,3386"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3983.0035,3400.9446 3983.0035,3400.4965 3988.756,3394.744 3988.756,3393.5802"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3996.772,3391.051 3991.449,3391.051 3988.9198,3393.5802 3988.756,3393.5802"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3983.0035,3408.1144 3983.0035,3404.4867"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3983.0035,3404.4867 3983.0035,3400.9446"},{"type":"polyline","net":"IO2","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3996.772,3397.35 3994.65,3397.35 3991,3401 3988.966,3401"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4043.425,3381.012 4054.512,3381.012 4055.118,3381.618 4055.118,3384.169"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4069.882,3384.169 4067.815,3382.102 4062.5,3382.102"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4062.5,3382.102 4057.898,3382.102 4055.831,3384.169 4055.118,3384.169"},{"type":"polyline","net":"IO9","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4035.748,3419.791 4035.748,3398.248 4035.5,3398"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4052.4176,3454.9176 4050.5,3453 4050.5,3448.5 4051.0512,3447.9488"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4061.016,3457.079 4054.579,3457.079 4052.4176,3454.9176"},{"type":"polyline","net":"VUSB","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4058.984,3448.921 4058.984,3448.0864 4054.9488,3444.0512"},{"type":"polyline","net":"VUSB","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3975.921,3454.016 3975.921,3448.579 3979.5,3445 3983.1024,3445 3984.0512,3444.0512"},{"type":"polyline","net":"VUSB","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3984.05,3444.05 3981.98,3441.98 3972.5,3441.98"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3990,3450.5 3990,3450 3987.9488,3447.9488"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3987.9488,3447.9488 3987.9488,3448.1142 3984.079,3451.984"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3996.575,3381.012 4043.425,3381.012"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M3974.72,3393.5 3983.24,3393.58"},{"start":[4029.5,3425],"end":[4029.5,3425],"width":2.441,"net":"HMOSI"},{"start":[4026.5,3425.5],"end":[4026.5,3425.5],"width":2.441,"net":"HCLK"},{"start":[4014,3416],"end":[4014,3416],"width":2.441,"net":"HCS"},{"start":[4007.5,3447.5],"end":[4007.5,3447.5],"width":2.441,"net":"LED_K"},{"start":[4013,3447.5],"end":[4013,3447.5],"width":2.441,"net":"3.3V"},{"start":[4032,3415.5],"end":[4032,3415.5],"width":2.441,"net":"REST"},{"start":[4021,3425.5],"end":[4021,3425.5],"width":2.441,"net":"DC"},{"start":[4035.5,3398],"end":[4035.5,3398],"width":2.441,"net":"IO9"},{"start":[4051.04,3393],"end":[4051.04,3393],"width":2.441,"net":"IO9"},{"start":[4000,3451.5],"end":[4000,3451.5],"width":2.441,"net":"DGND"},{"start":[4017.5,3426.5],"end":[4017.5,3426.5],"width":2.441,"net":"DGND"},{"start":[3969,3427.5],"end":[3969,3427.5],"width":2.441,"net":"DGND"},{"start":[3971.865,3444.789],"end":[3971.865,3444.789],"width":2.441,"net":"VUSB"},{"start":[3970.383,3442.422],"end":[3970.383,3442.422],"width":2.441,"net":"VUSB"},{"start":[3968.799,3439.569],"end":[3968.799,3439.569],"width":2.441,"net":"VUSB"},{"start":[3970,3430],"end":[3970,3430],"width":2.441,"net":"DGND"},{"start":[3968.5,3424.5],"end":[3968.5,3424.5],"width":2.441,"net":"DGND"},{"start":[3990,3450.5],"end":[3990,3450.5],"width":2.441,"net":"DGND"},{"start":[4052.418,3454.918],"end":[4052.418,3454.918],"width":2.441,"net":"DGND"},{"start":[3978,3386],"end":[3978,3386],"width":2.441,"net":"DGND"},{"start":[3974.5,3386],"end":[3974.5,3386],"width":2.441,"net":"DGND"},{"start":[3965.28,3388.463],"end":[3965.28,3388.463],"width":2.441,"net":"3.3V"},{"start":[4045,3430.534],"end":[4045,3430.534],"width":2.441,"net":"3.3V"},{"start":[4045,3427.5],"end":[4045,3427.5],"width":2.441,"net":"3.3V"},{"start":[4011.724,3408.276],"end":[4011.724,3408.276],"width":2.441,"net":"DGND"},{"start":[4020,3408.276],"end":[4020,3408.276],"width":2.441,"net":"DGND"},{"start":[4027.775,3408.276],"end":[4027.775,3408.276],"width":2.441,"net":"DGND"},{"start":[4027.775,3400.5],"end":[4027.775,3400.5],"width":2.441,"net":"DGND"},{"start":[4020,3400.5],"end":[4020,3400.5],"width":2.441,"net":"DGND"},{"start":[4012.224,3400.5],"end":[4012.224,3400.5],"width":2.441,"net":"DGND"},{"start":[4012.225,3392.725],"end":[4012.225,3392.725],"width":2.441,"net":"DGND"},{"start":[4020,3392.725],"end":[4020,3392.725],"width":2.441,"net":"DGND"},{"start":[4027.775,3392.725],"end":[4027.775,3392.725],"width":2.441,"net":"DGND"},{"start":[4048.5,3420],"end":[4048.5,3420],"width":2.441,"net":"DGND"}],"B":[{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4045,3430.53 4045,3424.5 4033,3412.5 3967.5,3412.5 3965.5,3410.5 3965.5,3388.68 3965.28,3388.46"},{"type":"polyline","net":"IO9","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4035.5,3398 4035.5,3395.5 4038,3393 4050.5,3393"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4045,3430.5339 4045,3427.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4000,3451.5 4000,3452.5 4002,3454.5 4004.7329,3454.5 4004.842,3454.3911"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4018.6201,3454.3899 4018.6201,3427.6201 4017.5,3426.5"},{"type":"polyline","net":"HCS","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4024.13,3454.39 4024.13,3418.13 4022,3416 4014,3416"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4035,3477.61 4035,3467.5 4031.9512,3464.7884"},{"type":"polyline","net":"VUSB","start":[0,0],"end":[0,0],"width":1.5748,"svgpath":"M4005,3477.61 4005,3469.259 4004.2271,3468.4861"},{"type":"polyline","net":"DC","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4021.377,3454.3911 4021.377,3425.877 4021,3425.5"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4010.353,3454.391 4013.109,3454.391"},{"type":"polyline","net":"3.3V","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4013,3447.5 4013,3454.2822 4013.1089,3454.3911"},{"type":"polyline","net":"HMOSI","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4029.645,3454.391 4029.645,3425.145 4029.5,3425"},{"type":"polyline","net":"REST","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4032.401,3454.391 4032.401,3415.901 4032,3415.5"},{"type":"polyline","net":"HCLK","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4026.8889,3454.3911 4026.8889,3425.8889 4026.5,3425.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M3990,3450.5 3986.35,3454.14"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4015.865,3454.391 4018.621,3454.391"},{"type":"polyline","net":"LED_K","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4007.6001,3454.3899 4007.5,3454.2898 4007.5,3447.5"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4004.84,3454.39 4004.84,3460.84 4005.5,3461.5 4015,3461.5 4016,3460.5 4016,3454.53 4015.86,3454.39"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4018.621,3454.391 4018.621,3461.121 4019,3461.5 4034.5,3461.5 4035,3461 4035,3454.548 4035.157,3454.391"},{"type":"polyline","net":"DGND","start":[0,0],"end":[0,0],"width":1,"svgpath":"M4035.157,3454.391 4051.891,3454.391 4052.4176,3454.9176"},{"start":[4029.5,3425],"end":[4029.5,3425],"width":2.441,"net":"HMOSI"},{"start":[4026.5,3425.5],"end":[4026.5,3425.5],"width":2.441,"net":"HCLK"},{"start":[4014,3416],"end":[4014,3416],"width":2.441,"net":"HCS"},{"start":[4007.5,3447.5],"end":[4007.5,3447.5],"width":2.441,"net":"LED_K"},{"start":[4013,3447.5],"end":[4013,3447.5],"width":2.441,"net":"3.3V"},{"start":[4032,3415.5],"end":[4032,3415.5],"width":2.441,"net":"REST"},{"start":[4021,3425.5],"end":[4021,3425.5],"width":2.441,"net":"DC"},{"start":[4035.5,3398],"end":[4035.5,3398],"width":2.441,"net":"IO9"},{"start":[4051.04,3393],"end":[4051.04,3393],"width":2.441,"net":"IO9"},{"start":[4000,3451.5],"end":[4000,3451.5],"width":2.441,"net":"DGND"},{"start":[4017.5,3426.5],"end":[4017.5,3426.5],"width":2.441,"net":"DGND"},{"start":[3969,3427.5],"end":[3969,3427.5],"width":2.441,"net":"DGND"},{"start":[3971.865,3444.789],"end":[3971.865,3444.789],"width":2.441,"net":"VUSB"},{"start":[3970.383,3442.422],"end":[3970.383,3442.422],"width":2.441,"net":"VUSB"},{"start":[3968.799,3439.569],"end":[3968.799,3439.569],"width":2.441,"net":"VUSB"},{"start":[3970,3430],"end":[3970,3430],"width":2.441,"net":"DGND"},{"start":[3968.5,3424.5],"end":[3968.5,3424.5],"width":2.441,"net":"DGND"},{"start":[3990,3450.5],"end":[3990,3450.5],"width":2.441,"net":"DGND"},{"start":[4052.418,3454.918],"end":[4052.418,3454.918],"width":2.441,"net":"DGND"},{"start":[3978,3386],"end":[3978,3386],"width":2.441,"net":"DGND"},{"start":[3974.5,3386],"end":[3974.5,3386],"width":2.441,"net":"DGND"},{"start":[3965.28,3388.463],"end":[3965.28,3388.463],"width":2.441,"net":"3.3V"},{"start":[4045,3430.534],"end":[4045,3430.534],"width":2.441,"net":"3.3V"},{"start":[4045,3427.5],"end":[4045,3427.5],"width":2.441,"net":"3.3V"},{"start":[4011.724,3408.276],"end":[4011.724,3408.276],"width":2.441,"net":"DGND"},{"start":[4020,3408.276],"end":[4020,3408.276],"width":2.441,"net":"DGND"},{"start":[4027.775,3408.276],"end":[4027.775,3408.276],"width":2.441,"net":"DGND"},{"start":[4027.775,3400.5],"end":[4027.775,3400.5],"width":2.441,"net":"DGND"},{"start":[4020,3400.5],"end":[4020,3400.5],"width":2.441,"net":"DGND"},{"start":[4012.224,3400.5],"end":[4012.224,3400.5],"width":2.441,"net":"DGND"},{"start":[4012.225,3392.725],"end":[4012.225,3392.725],"width":2.441,"net":"DGND"},{"start":[4020,3392.725],"end":[4020,3392.725],"width":2.441,"net":"DGND"},{"start":[4027.775,3392.725],"end":[4027.775,3392.725],"width":2.441,"net":"DGND"},{"start":[4048.5,3420],"end":[4048.5,3420],"width":2.441,"net":"DGND"}]},"zones":{"F":[],"B":[{"net":"DGND","svgpath":"M 4047.20883 3422.65283 L 4047.05532 3422.62279 4046.92506 3422.53618 4046.83799 3422.40623 4046.8074 3422.25283 4046.8074 3414.50462 4046.80569 3414.43041 4046.75772 3414.08659 4046.65183 3413.77065 4046.48969 3413.47954 4046.26495 3413.2089 4044.28129 3411.22524 4044.22761 3411.17398 4043.95057 3410.96477 4043.65229 3410.81625 4043.33179 3410.72506 4042.98151 3410.6926 3968.41434 3410.6926 3968.26126 3410.66215 3968.13149 3410.57544 3967.42456 3409.86851 3967.33785 3409.73874 3967.3074 3409.58566 3967.3074 3389.48031 3967.34291 3389.31555 3967.39115 3389.20882 3967.48685 3388.8413 3967.51905 3388.4629 3967.48685 3388.0845 3967.39115 3387.71698 3967.23473 3387.37092 3967.02206 3387.05628 3966.75929 3386.7821 3966.45395 3386.55628 3966.11485 3386.38531 3965.75172 3386.2741 3965.37503 3386.22586 3964.9956 3386.24198 3964.8121 3386.28153 3964.63438 3386.27944 3964.4751 3386.20055 3964.36573 3386.06044 3964.32785 3385.88679 3964.36895 3385.71386 3964.89484 3384.64599 3965.93348 3382.71236 3967.03995 3380.81673 3967.74174 3379.70639 3967.83102 3379.60693 3967.94808 3379.54243 3968.07986 3379.5201 4071.92055 3379.52 4072.05261 3379.54243 4072.16986 3379.6072 4072.25916 3379.70705 4073.03852 3380.94678 4074.13841 3382.84166 4075.17064 3384.77424 4076.1339 3386.74209 4077.027 3388.74277 4077.84883 3390.77377 4078.59834 3392.83254 4079.27461 3394.91653 4079.8768 3397.02312 4080.40414 3399.14968 4080.85598 3401.29355 4081.23175 3403.45205 4081.53099 3405.62249 4081.75332 3407.80214 4081.89847 3409.9883 4081.96624 3412.17822 4081.95656 3414.36917 4081.86944 3416.5584 4081.70499 3418.74319 4081.46341 3420.9208 4081.27704 3422.19065 4081.2321 3422.32472 4081.14332 3422.43478 4081.02179 3422.50707 4080.8827 3422.53256 4047.20883 3422.65283 Z M 4035.59503 3400.23704 L 4035.97172 3400.1888 4036.33485 3400.07759 4036.67395 3399.90662 4036.97929 3399.6808 4037.24206 3399.40662 4037.45473 3399.09198 4037.61115 3398.74592 4037.70685 3398.3784 4037.73905 3398 4037.70685 3397.6216 4037.61115 3397.25408 4037.45473 3396.90802 4037.24206 3396.59338 4037.17739 3396.5259 4037.09423 3396.39629 4037.06619 3396.24488 4037.09743 3396.09409 4037.18333 3395.96628 4038.51245 3394.63716 4038.64222 3394.55045 4038.79529 3394.52 4049.23927 3394.52 4049.3805 3394.54576 4049.50354 3394.61973 4049.70858 3394.80019 4050.03197 3394.99931 4050.38435 3395.14091 4050.7556 3395.22092 4051.13503 3395.23704 4051.51172 3395.1888 4051.87485 3395.07759 4052.21395 3394.90662 4052.51929 3394.6808 4052.78206 3394.40662 4052.99473 3394.09198 4053.15115 3393.74592 4053.24685 3393.3784 4053.27905 3393 4053.24685 3392.6216 4053.15115 3392.25408 4052.99473 3391.90802 4052.78206 3391.59338 4052.51929 3391.3192 4052.21395 3391.09338 4051.87485 3390.92241 4051.51172 3390.8112 4051.13503 3390.76296 4050.7556 3390.77908 4050.38435 3390.85909 4050.03197 3391.00069 4049.70858 3391.19981 4049.50354 3391.38027 4049.3805 3391.45424 4049.23927 3391.48 4038.01965 3391.48 4037.70384 3391.5111 4037.41906 3391.59749 4037.15661 3391.73778 4036.9113 3391.93909 4034.43909 3394.4113 4034.23778 3394.65661 4034.09749 3394.91906 4034.0111 3395.20384 4033.98 3395.51965 4033.98 3396.18987 4033.95715 3396.32313 4033.89121 3396.44116 4033.64492 3396.74619 4033.45971 3397.07773 4033.33319 3397.43581 4033.26901 3397.81011 4033.26901 3398.18989 4033.33319 3398.56419 4033.45971 3398.92227 4033.64492 3399.25381 4033.8835 3399.54929 4034.16858 3399.80019 4034.49197 3399.99931 4034.84435 3400.14091 4035.2156 3400.22092 4035.59503 3400.23704 Z "}]},"pads":[{"layers":["F","B"],"pos":[4025,3477.61],"size":[7.874,7.874],"angle":-180,"pin1":1,"shape":"oval","type":"th","drillsize":[3.3464,3.3464],"holeCenterPoint":{"x":4025.0003,"y":3477.6104},"polygon":[],"net":"U4_3"},{"layers":["F","B"],"pos":[4015,3477.61],"size":[7.874,7.874],"angle":-180,"pin1":1,"shape":"oval","type":"th","drillsize":[3.3464,3.3464],"holeCenterPoint":{"x":4014.9998,"y":3477.6104},"polygon":[],"net":"U4_2"},{"layers":["F","B"],"pos":[4035,3477.61],"size":[7.874,7.874],"angle":-180,"pin1":1,"shape":"oval","type":"th","drillsize":[3.3464,3.3464],"holeCenterPoint":{"x":4035.0003,"y":3477.6104},"polygon":[],"net":"DGND"},{"layers":["F","B"],"pos":[4005,3477.61],"size":[7.874,7.874],"angle":-180,"pin1":1,"shape":"oval","type":"th","drillsize":[3.3464,3.3464],"holeCenterPoint":{"x":4004.9998,"y":3477.6104},"polygon":[],"net":"VUSB"}],"nets":["U4_3","U4_2","DGND","VUSB","HMOSI","HCLK","HCS","LED_K","3.3V","REST","DC","IO9","IO0","BLK","IO8","USB_D-","USB_D+","LED3_4","R2_1","Q1_3","EN","IO2","IO3","CAN_RX","CAN_TX"],"bom":{"both":[[1,"GC9A01_IPS_display_SPI","GC9A01_IPS_DISPLAY",[["U2",0]],[" "," "," "," "]],[2,"0.8R","R0603",[["R6",1],["R7",2]],[" "," "," "," "]],[4,"100n","C0603",[["C8",3],["C9",4],["C5",12],["C1",20]],[" "," "," "," "]],[2,"WS2812B-MINI","LED-SMD_4P-L2.0-W2.0-TL_WS2812B-2020",[["LED2",5],["LED3",6]],[" "," "," "," "]],[1,"pg","SW-SMD_L3.1-W3.1-P2.20-LS4.0",[["SW1",7]],[" "," "," "," "]],[3,"10k","R0603",[["R5",8],["R3",15],["R4",16]],[" "," "," "," "]],[3,"10uF","C0603",[["C2",9],["C4",11],["C7",14]],[" "," "," "," "]],[1,"1u","C0603",[["C3",10]],[" "," "," "," "]],[1,"22uF","CASE-A_3216",[["C6",13]],[" "," "," "," "]],[1,"AMS1117S-3.3","SOT-89-3_L4.5-W2.5-P1.50-LS4.1-BR",[["U3",17]],[" "," "," "," "]],[1,"S8050-G_C164892","SOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR",[["Q1",18]],[" "," "," "," "]],[1,"ESP32-C3-MINI-1-N4","WIFIM-SMD_ESP32-C3-MINI-1",[["U1",19]],[" "," "," "," "]],[1,"10","R0603_NEW",[["R1",21]],[" "," "," "," "]],[1,"1K","R0603_NEW",[["R2",22]],[" "," "," "," "]]],"F":[[2,"0.8R","R0603",[["R6",1],["R7",2]],[" "," "," "," "]],[4,"100n","C0603",[["C8",3],["C9",4],["C5",12],["C1",20]],[" "," "," "," "]],[2,"WS2812B-MINI","LED-SMD_4P-L2.0-W2.0-TL_WS2812B-2020",[["LED2",5],["LED3",6]],[" "," "," "," "]],[1,"pg","SW-SMD_L3.1-W3.1-P2.20-LS4.0",[["SW1",7]],[" "," "," "," "]],[3,"10k","R0603",[["R5",8],["R3",15],["R4",16]],[" "," "," "," "]],[3,"10uF","C0603",[["C2",9],["C4",11],["C7",14]],[" "," "," "," "]],[1,"1u","C0603",[["C3",10]],[" "," "," "," "]],[1,"22uF","CASE-A_3216",[["C6",13]],[" "," "," "," "]],[1,"AMS1117S-3.3","SOT-89-3_L4.5-W2.5-P1.50-LS4.1-BR",[["U3",17]],[" "," "," "," "]],[1,"S8050-G_C164892","SOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR",[["Q1",18]],[" "," "," "," "]],[1,"ESP32-C3-MINI-1-N4","WIFIM-SMD_ESP32-C3-MINI-1",[["U1",19]],[" "," "," "," "]],[1,"10","R0603_NEW",[["R1",21]],[" "," "," "," "]],[1,"1K","R0603_NEW",[["R2",22]],[" "," "," "," "]]],"B":[[1,"GC9A01_IPS_display_SPI","GC9A01_IPS_DISPLAY",[["U2",0]],[" "," "," "," "]]],"skipped":[],"customColumns":[]}};
///////////////////////////////////////////////

///////////////////////////////////////////////
/* Utility functions */

var storagePrefix = 'ibom__' + pcbdata.metadata.title + '__' +
  pcbdata.metadata.revision + '__#';

function buildKeyForLocalStorageDict() {  
  return storagePrefix;
}

var storage;
var _isLocalStorageUsed = false;

function initStorage(key) {
  try {
    window.localStorage.getItem("blank");
    storage = window.localStorage;    
    _isLocalStorageUsed = true;
  } catch (e) {
    // localStorage not available
  }
  if (!storage) {
    try {
      window.sessionStorage.getItem("blank");
      storage = window.sessionStorage;      
    } catch (e) {
      // sessionStorage also not available
    }
  }
}



function readStorage(key) {
  if(!storage) {
    return null;
  }

  if(!_isLocalStorageUsed) {    
    return storage.getItem(storagePrefix + key);
  }

  try {
    var dictKey = buildKeyForLocalStorageDict();
    var obj = JSON.parse(storage.getItem(dictKey));    
    if(!obj || !obj.hasOwnProperty(key)) {
      return null;
    }

    return JSON.parse(storage.getItem(dictKey))[key];
  } catch(e) {
    console.log('[ibom]: Unable to obtain a value from local storage!');
    console.log(e);
  }
  
  // Original implementation
  // return storage.getItem(storagePrefix + key);
}


function writeStorage(key, value) {
  if(!storage) {
    return;
  }

  if(!_isLocalStorageUsed) {
    storage.setItem(storagePrefix + key, value);
    return;
  }

  try {
    var dictKey = buildKeyForLocalStorageDict();
    if(!storage.getItem(dictKey)) {
      storage.setItem(dictKey,JSON.stringify({
        _storagePrefix: storagePrefix
      }));
    }

    var obj = JSON.parse(storage.getItem(dictKey));
    obj[key] = value;
    storage.setItem(dictKey,JSON.stringify(obj));            
  } catch(e) {
    console.log('[ibom]: Unable to write key to local storage!');
    console.log(e);
  }
  
  // Original implementation
  // storage.setItem(storagePrefix + key, value);
}

function fancyDblClickHandler(el, onsingle, ondouble) {
  return function() {
    if (el.getAttribute("data-dblclick") == null) {
      el.setAttribute("data-dblclick", 1);
      setTimeout(function() {
        if (el.getAttribute("data-dblclick") == 1) {
          onsingle();
        }
        el.removeAttribute("data-dblclick");
      }, 200);
    } else {
      el.removeAttribute("data-dblclick");
      ondouble();
    }
  }
}

function smoothScrollToRow(rowid) {
  document.getElementById(rowid).scrollIntoView({
    behavior: "smooth",
    block: "center",
    inline: "nearest"
  });
}

function focusInputField(input) {
  input.scrollIntoView(false);
  input.focus();
  input.select();
}

function copyToClipboard() {
  var text = '';
  for (var node of bomhead.childNodes[0].childNodes) {
    if (node.firstChild) {
      text = text + node.firstChild.nodeValue;
    }
    if (node != bomhead.childNodes[0].lastChild) {
      text += '\t';
    }
  }
  text += '\n';
  for (var row of bombody.childNodes) {
    for (var cell of row.childNodes) {
      for (var node of cell.childNodes) {
        if (node.nodeName == "INPUT") {
          if (node.checked) {
            text = text + '✓';
          }
        } else if (node.nodeName == "MARK") {
          text = text + node.firstChild.nodeValue;
        } else {
          text = text + node.nodeValue;
        }
      }
      if (cell != row.lastChild) {
        text += '\t';
      }
    }
    text += '\n';
  }
  var textArea = document.createElement("textarea");
  textArea.classList.add('clipboard-temp');
  textArea.value = text;

  document.body.appendChild(textArea);
  textArea.focus();
  textArea.select();

  try {
    if (document.execCommand('copy')) {
      console.log('Bom copied to clipboard.');
    }
  } catch (err) {
    console.log('Can not copy to clipboard.');
  }

  document.body.removeChild(textArea);
}

function removeGutterNode(node) {
  for (var i = 0; i < node.childNodes.length; i++) {
    if (node.childNodes[i].classList &&
      node.childNodes[i].classList.contains("gutter")) {
      node.removeChild(node.childNodes[i]);
      break;
    }
  }
}

function cleanGutters() {
  removeGutterNode(document.getElementById("bot"));
  removeGutterNode(document.getElementById("canvasdiv"));
}

var units = {
  prefixes: {
    giga: ["G", "g", "giga", "Giga", "GIGA"],
    mega: ["M", "mega", "Mega", "MEGA"],
    kilo: ["K", "k", "kilo", "Kilo", "KILO"],
    milli: ["m", "milli", "Milli", "MILLI"],
    micro: ["U", "u", "micro", "Micro", "MICRO", "μ", "µ"], // different utf8 μ
    nano: ["N", "n", "nano", "Nano", "NANO"],
    pico: ["P", "p", "pico", "Pico", "PICO"],
  },
  unitsShort: ["R", "r", "Ω", "F", "f", "H", "h"],
  unitsLong: [
    "OHM", "Ohm", "ohm", "ohms",
    "FARAD", "Farad", "farad",
    "HENRY", "Henry", "henry"
  ],
  getMultiplier: function(s) {
    if (this.prefixes.giga.includes(s)) return 1e9;
    if (this.prefixes.mega.includes(s)) return 1e6;
    if (this.prefixes.kilo.includes(s)) return 1e3;
    if (this.prefixes.milli.includes(s)) return 1e-3;
    if (this.prefixes.micro.includes(s)) return 1e-6;
    if (this.prefixes.nano.includes(s)) return 1e-9;
    if (this.prefixes.pico.includes(s)) return 1e-12;
    return 1;
  },
  valueRegex: null,
}

function initUtils() {
  var allPrefixes = units.prefixes.giga
                    .concat(units.prefixes.mega)
                    .concat(units.prefixes.kilo)
                    .concat(units.prefixes.milli)
                    .concat(units.prefixes.micro)
                    .concat(units.prefixes.nano)
                    .concat(units.prefixes.pico);
  var allUnits = units.unitsShort.concat(units.unitsLong);
  units.valueRegex = new RegExp("^([0-9\.]+)" +
                         "\\s*(" + allPrefixes.join("|") + ")?" +
                         "(" + allUnits.join("|") + ")?" +
                         "(\\b.*)?$", "");
  units.valueAltRegex = new RegExp("^([0-9]*)" +
                         "(" + units.unitsShort.join("|") + ")?" +
                         "([GgMmKkUuNnPp])?" +
                         "([0-9]*)" +
                         "(\\b.*)?$", "");
  for (var bom_type of ["both", "F", "B"]) {
    for (var row of pcbdata.bom[bom_type]) {
      row.push(parseValue(row[1], row[3][0][0]));
    }
  }
}

function parseValue(val, ref) {
  var inferUnit = (unit, ref) => {
    if (unit) {
      unit = unit.toLowerCase();
      if (unit == 'Ω' || unit == "ohm" || unit == "ohms") {
        unit = 'r';
      }
      unit = unit[0];
    } else {
      ref = /^([a-z]+)\d+$/i.exec(ref);
      if (ref) {
        ref = ref[1].toLowerCase();
        if (ref == "c") unit = 'f';
        else if (ref == "l") unit = 'h';
        else if (ref == "r" || ref == "rv") unit = 'r';
        else unit = null;
      }
    }
    return unit;
  };
  val = val.replace(/,/g, "");
  var match = units.valueRegex.exec(val);
  var unit;
  if (match) {
    val = parseFloat(match[1]);
    if (match[2]) {
      val = val * units.getMultiplier(match[2]);
    }
    unit = inferUnit(match[3], ref);
    if (!unit) return null;
    else return {
      val: val,
      unit: unit,
      extra: match[4],
    }
  }
  match = units.valueAltRegex.exec(val);
  if (match && (match[1] || match[4])) {
    val = parseFloat(match[1] + "." + match[4]);
    if (match[3]) {
      val = val * units.getMultiplier(match[3]);
    }
    unit = inferUnit(match[2], ref);
    if (!unit) return null;
    else return {
      val: val,
      unit: unit,
      extra: match[5],
    }
  }
  return null;
}

function valueCompare(a, b, stra, strb) {
  if (a === null && b === null) {
    // Failed to parse both values, compare them as strings.
    if (stra != strb) return stra > strb ? 1 : -1;
    else return 0;
  } else if (a === null) {
    return 1;
  } else if (b === null) {
    return -1;
  } else {
    if (a.unit != b.unit) return a.unit > b.unit ? 1 : -1;
    else if (a.val != b.val) return a.val > b.val ? 1 : -1;
    else if (a.extra != b.extra) return a.extra > b.extra ? 1 : -1;
    else return 0;
  }
}

function validateSaveImgDimension(element) {
  var valid = false;
  var intValue = 0;
  if (/^[1-9]\d*$/.test(element.value)) {
    intValue = parseInt(element.value);
    if (intValue <= 16000) {
      valid = true;
    }
  }
  if (valid) {
    element.classList.remove("invalid");
  } else {
    element.classList.add("invalid");
  }
  return intValue;
}

function saveImage(layer) {
  var width = validateSaveImgDimension(document.getElementById("render-save-width"));
  var height = validateSaveImgDimension(document.getElementById("render-save-height"));
  var bgcolor = null;
  if (!document.getElementById("render-save-transparent").checked) {
    var style = getComputedStyle(topmostdiv);
    bgcolor = style.getPropertyValue("background-color");
  }
  if (!width || !height) return;

  // Prepare image
  var canvas = document.createElement("canvas");
  var layerdict = {
    transform: {
      x: 0,
      y: 0,
      s: 1,
      panx: 0,
      pany: 0,
      zoom: 1,
    },
    bg: canvas,
    fab: canvas,
    silk: canvas,
    highlight: canvas,
    layer: layer,
  }
  // Do the rendering
  recalcLayerScale(layerdict, width, height);
  prepareLayer(layerdict);
  clearCanvas(canvas, bgcolor);
  drawBackground(layerdict, false);
  drawHighlightsOnLayer(layerdict, false);

  // Save image
  var imgdata = canvas.toDataURL("image/png");

  var filename = pcbdata.metadata.title;
  if (pcbdata.metadata.revision) {
    filename += `.${pcbdata.metadata.revision}`;
  }
  filename += `.${layer}.png`;
  saveFile(filename, dataURLtoBlob(imgdata));
}

function saveSettings() {
  var data = {
    type: "InteractiveHtmlBom settings",
    version: 1,
    pcbmetadata: pcbdata.metadata,
    settings: settings,
  }
  var blob = new Blob([JSON.stringify(data, null, 4)], {type: "application/json"});
  saveFile(`${pcbdata.metadata.title}.settings.json`, blob);
}

function loadSettings() {
  var input = document.createElement("input");
  input.type = "file";
  input.accept = ".settings.json";
  input.onchange = function(e) {
    var file = e.target.files[0];
    var reader = new FileReader();
    reader.onload = readerEvent => {
      var content = readerEvent.target.result;
      var newSettings;
      try {
        newSettings = JSON.parse(content);
      } catch(e) {
        alert("Selected file is not InteractiveHtmlBom settings file.");
        return;
      }
      if (newSettings.type != "InteractiveHtmlBom settings") {
        alert("Selected file is not InteractiveHtmlBom settings file.");
        return;
      }
      var metadataMatches = newSettings.hasOwnProperty("pcbmetadata");
      if (metadataMatches) {
        for (var k in pcbdata.metadata) {
          if (!newSettings.pcbmetadata.hasOwnProperty(k) || newSettings.pcbmetadata[k] != pcbdata.metadata[k]) {
            metadataMatches = false;
          }
        }
      }
      if (!metadataMatches) {
        var currentMetadata = JSON.stringify(pcbdata.metadata, null, 4);
        var fileMetadata = JSON.stringify(newSettings.pcbmetadata, null, 4);
        if (!confirm(
          `Settins file metadata does not match current metadata.\n\n` +
          `Page metadata:\n${currentMetadata}\n\n` +
          `Settings file metadata:\n${fileMetadata}\n\n` +
          `Press OK if you would like to import settings anyway.`)) {
          return;
        }
      }
      overwriteSettings(newSettings.settings);
    }
    reader.readAsText(file, 'UTF-8');
  }
  input.click();
}

function overwriteSettings(newSettings) {

  initDone = false;
  Object.assign(settings, newSettings);
  writeStorage("bomlayout", settings.bomlayout);
  writeStorage("bommode", settings.bommode);
  writeStorage("canvaslayout", settings.canvaslayout);
  writeStorage("bomCheckboxes", settings.checkboxes.join(","));
  document.getElementById("bomCheckboxes").value = settings.checkboxes.join(",");
  for (var checkbox of settings.checkboxes) {
    writeStorage("checkbox_" + checkbox, settings.checkboxStoredRefs[checkbox]);
  }
  writeStorage("darkenWhenChecked", settings.darkenWhenChecked);
  padsVisible(settings.renderPads);
  document.getElementById("padsCheckbox").checked = settings.renderPads;
  fabricationVisible(settings.renderFabrication);
  document.getElementById("fabricationCheckbox").checked = settings.renderFabrication;
  silkscreenVisible(settings.renderSilkscreen);
  document.getElementById("silkscreenCheckbox").checked = settings.renderSilkscreen;
  referencesVisible(settings.renderReferences);
  document.getElementById("referencesCheckbox").checked = settings.renderReferences;
  valuesVisible(settings.renderValues);
  document.getElementById("valuesCheckbox").checked = settings.renderValues;
  tracksVisible(settings.renderTracks);
  document.getElementById("tracksCheckbox").checked = settings.renderTracks;
  zonesVisible(settings.renderZones);
  document.getElementById("zonesCheckbox").checked = settings.renderZones;
  dnpOutline(settings.renderDnpOutline);
  document.getElementById("dnpOutlineCheckbox").checked = settings.renderDnpOutline;
  setRedrawOnDrag(settings.redrawOnDrag);
  document.getElementById("dragCheckbox").checked = settings.redrawOnDrag;
  setShowCrosshair(settings.showCrosshair);
  document.getElementById("crosshairCheckbox").checked = settings.showCrosshair;
  setDarkMode(settings.darkMode);
  document.getElementById("darkmodeCheckbox").checked = settings.darkMode;
  setHighlightPin1(settings.highlightpin1);
  document.getElementById("highlightpin1Checkbox").checked = settings.highlightpin1;
  writeStorage("boardRotation", settings.boardRotation);
  document.getElementById("boardRotation").value = settings.boardRotation / 5;
  document.getElementById("rotationDegree").textContent = settings.boardRotation;
  initDone = true;
  prepCheckboxes();
  changeBomLayout(settings.bomlayout);
}

function saveFile(filename, blob) {
  var link = document.createElement("a");
  var objurl = URL.createObjectURL(blob);
  link.download = filename;
  link.href = objurl;
  link.click();
}

function dataURLtoBlob(dataurl) {
  var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
      bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
  while(n--){
      u8arr[n] = bstr.charCodeAt(n);
  }
  return new Blob([u8arr], {type:mime});
}

var settings = {
  canvaslayout: "default",
  bomlayout: "default",
  bommode: "grouped",
  checkboxes: [],
  checkboxStoredRefs: {},
  darkMode: false,
  highlightpin1: false,
  redrawOnDrag: true,
  boardRotation: 0,
  renderPads: true,
  renderReferences: true,
  renderValues: true,
  renderSilkscreen: true,
  renderFabrication: true,
  renderDnpOutline: false,
  renderTracks: true,
  renderZones: true,
}

function initDefaults() {
  settings.bomlayout = readStorage("bomlayout");
  if (settings.bomlayout === null) {
    settings.bomlayout = config.bom_view;
  }
  if (!['bom-only', 'left-right', 'top-bottom'].includes(settings.bomlayout)) {
    settings.bomlayout = config.bom_view;
  }
  settings.bommode = readStorage("bommode");
  if (settings.bommode === null) {
    settings.bommode = "grouped";
  }
  if (!["grouped", "ungrouped", "netlist"].includes(settings.bommode)) {
    settings.bommode = "grouped";
  }
  settings.canvaslayout = readStorage("canvaslayout");
  if (settings.canvaslayout === null) {
    settings.canvaslayout = config.layer_view;
  }
  var bomCheckboxes = readStorage("bomCheckboxes");
  if (bomCheckboxes === null) {
    bomCheckboxes = config.checkboxes;
  }
  settings.checkboxes = bomCheckboxes.split(",").filter((e) => e);
  document.getElementById("bomCheckboxes").value = bomCheckboxes;

  settings.darkenWhenChecked = readStorage("darkenWhenChecked") || "";
  populateDarkenWhenCheckedOptions();

  function initBooleanSetting(storageString, def, elementId, func) {    
    var b = readStorage(storageString);
    if (b === null) {
      b = def;
    } else {
      b = (b === true);
    }
    document.getElementById(elementId).checked = b;
    func(b);
  }

  initBooleanSetting("padsVisible", config.show_pads, "padsCheckbox", padsVisible);
  initBooleanSetting("fabricationVisible", config.show_fabrication, "fabricationCheckbox", fabricationVisible);
  initBooleanSetting("silkscreenVisible", config.show_silkscreen, "silkscreenCheckbox", silkscreenVisible);
  initBooleanSetting("referencesVisible", true, "referencesCheckbox", referencesVisible);
  initBooleanSetting("valuesVisible", false, "valuesCheckbox", valuesVisible);
  if ("tracks" in pcbdata) {
    initBooleanSetting("tracksVisible", true, "tracksCheckbox", tracksVisible);
    initBooleanSetting("zonesVisible", true, "zonesCheckbox", zonesVisible);
  } else {
    document.getElementById("tracksAndZonesCheckboxes").style.display = "none";
    tracksVisible(false);
    zonesVisible(false);
  }
  initBooleanSetting("dnpOutline", false, "dnpOutlineCheckbox", dnpOutline);
  initBooleanSetting("redrawOnDrag", config.redraw_on_drag, "dragCheckbox", setRedrawOnDrag);
  initBooleanSetting("showCrosshair", config.show_crosshair, "crosshairCheckbox", setShowCrosshair);
  initBooleanSetting("darkmode", config.dark_mode, "darkmodeCheckbox", setDarkMode);
  initBooleanSetting("highlightpin1", config.highlight_pin1, "highlightpin1Checkbox", setHighlightPin1);
  settings.boardRotation = readStorage("boardRotation");
  if (settings.boardRotation === null) {
    settings.boardRotation = config.board_rotation * 5;
  } else {
    settings.boardRotation = parseInt(settings.boardRotation);
  }
  document.getElementById("boardRotation").value = settings.boardRotation / 5;
  document.getElementById("rotationDegree").textContent = settings.boardRotation;
}

// Helper classes for user js callbacks.

const IBOM_EVENT_TYPES = {
  ALL: "all",
  HIGHLIGHT_EVENT: "highlightEvent",
  CHECKBOX_CHANGE_EVENT: "checkboxChangeEvent",
  BOM_BODY_CHANGE_EVENT: "bomBodyChangeEvent",
}

const EventHandler = {
  callbacks: {},
  init: function() {
    for (eventType of Object.values(IBOM_EVENT_TYPES))
      this.callbacks[eventType] = [];
  },
  registerCallback: function(eventType, callback) {
    this.callbacks[eventType].push(callback);
  },
  emitEvent: function(eventType, eventArgs) {
    event = {
      eventType: eventType,
      args: eventArgs,
    }
    var callback;
    for(callback of this.callbacks[eventType])
      callback(event);
    for(callback of this.callbacks[IBOM_EVENT_TYPES.ALL])
      callback(event);
  }
}
EventHandler.init();

///////////////////////////////////////////////

///////////////////////////////////////////////
/* PCB rendering code */

var emptyContext2d = document.createElement("canvas").getContext("2d");
var hitTestContext2d = document.createElement("canvas").getContext("2d");

function deg2rad(deg) {
  return deg * Math.PI / 180;
}

function calcFontPoint(linepoint, text, offsetx, offsety, tilt) {
  var point = [
    linepoint[0] * text.width + offsetx,
    linepoint[1] * text.height + offsety
  ];
  // This approximates pcbnew behavior with how text tilts depending on horizontal justification
  point[0] -= (linepoint[1] + 0.5 * (1 + text.justify[0])) * text.height * tilt;
  return point;
}

function drawText(ctx, text, color) {
  if ("ref" in text && !settings.renderReferences) return;
  if ("val" in text && !settings.renderValues) return;
  ctx.save();
  ctx.fillStyle = color;
  ctx.strokeStyle = color;
  ctx.lineCap = "round";
  ctx.lineJoin = "round";
  ctx.lineWidth = text.thickness;

  if ("svgpath" in text) {    
    // TODO: This path must be cached!
    const path = new Path2D(text.svgpath);
    if(text.useTrueTypeFontRendering) {            
      ctx.fill(path);
    } else {
      ctx.stroke(path);
    }
    
    ctx.restore();
    return;
  }

  ctx.translate(...text.pos);
  ctx.translate(text.thickness * 0.5, 0);
  var angle = -text.angle;
  if (text.attr.includes("mirrored")) {
    ctx.scale(-1, 1);
    angle = -angle;
  }
  var tilt = 0;
  if (text.attr.includes("italic")) {
    tilt = 0.125;
  }
  var interline = text.height * 1.5 + text.thickness;
  var txt = text.text.split("\n");
  // KiCad ignores last empty line.
  if (txt[txt.length - 1] == '') txt.pop();
  ctx.rotate(deg2rad(angle));
  var offsety = (1 - text.justify[1]) / 2 * text.height; // One line offset
  offsety -= (txt.length - 1) * (text.justify[1] + 1) / 2 * interline; // Multiline offset
  for (var i in txt) {
    var lineWidth = text.thickness + interline / 2 * tilt;
    for (var j = 0; j < txt[i].length; j++) {
      if (txt[i][j] == '\t') {
        var fourSpaces = 4 * pcbdata.font_data[' '].w * text.width;
        lineWidth += fourSpaces - lineWidth % fourSpaces;
      } else {
        if (txt[i][j] == '~') {
          j++;
          if (j == txt[i].length)
            break;
        }
        lineWidth += pcbdata.font_data[txt[i][j]].w * text.width;
      }
    }
    var offsetx = -lineWidth * (text.justify[0] + 1) / 2;
    var inOverbar = false;
    for (var j = 0; j < txt[i].length; j++) {
      if (txt[i][j] == '\t') {
        var fourSpaces = 4 * pcbdata.font_data[' '].w * text.width;
        offsetx += fourSpaces - offsetx % fourSpaces;
        continue;
      } else if (txt[i][j] == '~') {
        j++;
        if (j == txt[i].length)
          break;
        if (txt[i][j] != '~') {
          inOverbar = !inOverbar;
        }
      }
      var glyph = pcbdata.font_data[txt[i][j]];
      if (inOverbar) {
        var overbarStart = [offsetx, -text.height * 1.4 + offsety];
        var overbarEnd = [offsetx + text.width * glyph.w, overbarStart[1]];

        if (!lastHadOverbar) {
          overbarStart[0] += text.height * 1.4 * tilt;
          lastHadOverbar = true;
        }
        ctx.beginPath();
        ctx.moveTo(...overbarStart);
        ctx.lineTo(...overbarEnd);
        ctx.stroke();
      } else {
        lastHadOverbar = false;
      }
      for (var line of glyph.l) {
        ctx.beginPath();
        ctx.moveTo(...calcFontPoint(line[0], text, offsetx, offsety, tilt));
        for (var k = 1; k < line.length; k++) {
          ctx.lineTo(...calcFontPoint(line[k], text, offsetx, offsety, tilt));
        }
        ctx.stroke();
      }
      offsetx += glyph.w * text.width;
    }
    offsety += interline;
  }
  ctx.restore();
}

function drawedge(ctx, scalefactor, edge, color) {
  ctx.strokeStyle = color;
  ctx.lineWidth = Math.max(1 / scalefactor, edge.width);
  ctx.lineCap = "round";
  if ("svgpath" in edge) {
    ctx.stroke(new Path2D(edge.svgpath));
  } else {
    ctx.beginPath();
    if (edge.type == "segment") {
      ctx.moveTo(...edge.start);
      ctx.lineTo(...edge.end);
    }
    if (edge.type == "rect") {
      ctx.moveTo(...edge.start);
      ctx.lineTo(edge.start[0], edge.end[1]);
      ctx.lineTo(...edge.end);
      ctx.lineTo(edge.end[0], edge.start[1]);
      ctx.lineTo(...edge.start);
    }
    if (edge.type == "arc") {
      ctx.arc(
        ...edge.start,
        edge.radius,
        deg2rad(edge.startangle),
        deg2rad(edge.endangle));
    }
    if (edge.type == "circle") {
      ctx.arc(
        ...edge.start,
        edge.radius,
        0, 2 * Math.PI);
      ctx.closePath();
    }
    if (edge.type == "curve") {
      ctx.moveTo(...edge.start);
      ctx.bezierCurveTo(...edge.cpa, ...edge.cpb, ...edge.end);
    }
    ctx.stroke();
  }
}

function getChamferedRectPath(size, radius, chamfpos, chamfratio) {
  // chamfpos is a bitmask, left = 1, right = 2, bottom left = 4, bottom right = 8
  var path = new Path2D();
  var width = size[0];
  var height = size[1];
  var x = width * -0.5;
  var y = height * -0.5;
  var chamfOffset = Math.min(width, height) * chamfratio;
  path.moveTo(x, 0);
  if (chamfpos & 4) {
    path.lineTo(x, y + height - chamfOffset);
    path.lineTo(x + chamfOffset, y + height);
    path.lineTo(0, y + height);
  } else {
    path.arcTo(x, y + height, x + width, y + height, radius);
  }
  if (chamfpos & 8) {
    path.lineTo(x + width - chamfOffset, y + height);
    path.lineTo(x + width, y + height - chamfOffset);
    path.lineTo(x + width, 0);
  } else {
    path.arcTo(x + width, y + height, x + width, y, radius);
  }
  if (chamfpos & 2) {
    path.lineTo(x + width, y + chamfOffset);
    path.lineTo(x + width - chamfOffset, y);
    path.lineTo(0, y);
  } else {
    path.arcTo(x + width, y, x, y, radius);
  }
  if (chamfpos & 1) {
    path.lineTo(x + chamfOffset, y);
    path.lineTo(x, y + chamfOffset);
    path.lineTo(x, 0);
  } else {
    path.arcTo(x, y, x, y + height, radius);
  }
  path.closePath();
  return path;
}

function getOblongPath(size) {
  return getChamferedRectPath(size, Math.min(size[0], size[1]) / 2, 0, 0);
}

function getPolygonsPath(shape) {
  if (shape.path2d) {
    return shape.path2d;
  }
  if ("svgpath" in shape) {
    shape.path2d = new Path2D(shape.svgpath);
  } else {
    var path = new Path2D();
    for (var polygon of shape.polygons) {
      path.moveTo(...polygon[0]);
      for (var i = 1; i < polygon.length; i++) {
        path.lineTo(...polygon[i]);
      }
      path.closePath();
    }
    shape.path2d = path;
  }
  return shape.path2d;
}

function drawPolygonShape(ctx, shape, color) {
  ctx.save();
  ctx.fillStyle = color;
  if (!("svgpath" in shape)) {
    ctx.translate(...shape.pos);
    ctx.rotate(deg2rad(-shape.angle));
  }
  ctx.fill(getPolygonsPath(shape));
  ctx.restore();
}


function drawPolylineShape(ctx, shape, color) {
  ctx.save();
  ctx.strokeStyle = color;
  ctx.lineWidth = shape.width;
  if (!("svgpath" in shape)) {
    ctx.translate(...shape.pos);
    ctx.rotate(deg2rad(-shape.angle));
  }
  ctx.stroke(getPolygonsPath(shape));
  ctx.restore();
}

function drawDrawing(ctx, scalefactor, drawing, color) {  
  if (["segment", "arc", "circle", "curve"].includes(drawing.type)) {
    drawedge(ctx, scalefactor, drawing, color);
  } else if (drawing.type == "polygon") {
    drawPolygonShape(ctx, drawing, color);
  } else if (drawing.type == "text") {    
    drawText(ctx, drawing, color);
  } else if (drawing.type == "polyline") {    
    drawPolylineShape(ctx, drawing, color);
  }
}

function getCirclePath(radius) {
  var path = new Path2D();
  path.arc(0, 0, radius, 0, 2 * Math.PI);
  path.closePath();
  return path;
}

function getCachedPadPath(pad) {
  if (!pad.path2d) {
    // if path2d is not set, build one and cache it on pad object
    if (pad.shape == "rect") {
      pad.path2d = new Path2D();
      pad.path2d.rect(...pad.size.map(c => -c * 0.5), ...pad.size);
    } else if (pad.shape == "oval") {
      pad.path2d = getOblongPath(pad.size);
    } else if (pad.shape == "circle") {
      pad.path2d = getCirclePath(pad.size[0] / 2);
    } else if (pad.shape == "roundrect") {
      pad.path2d = getChamferedRectPath(pad.size, pad.radius, 0, 0);
    } else if (pad.shape == "chamfrect") {
      pad.path2d = getChamferedRectPath(pad.size, pad.radius, pad.chamfpos, pad.chamfratio)
    } else if (pad.shape == "custom") {
      pad.path2d = getPolygonsPath(pad);
    } else if(pad.shape === "polygon") {      
      pad.path2d = new Path2D();
      if(pad.polygon.length > 1) {
        const pos = {
          x: pad.pos[0],
          y: pad.pos[1]
        };

        pad.path2d.moveTo(pad.polygon[0].x - pos.x, pad.polygon[0].y - pos.y);
        for (var i = 1; i < pad.polygon.length; i++) {
          const point = pad.polygon[i];          
          pad.path2d.lineTo(point.x - pos.x, point.y - pos.y);
        }
        pad.path2d.closePath();              
      }
    }
  }
  return pad.path2d;
}

function drawPad(ctx, pad, color, outline) {
  ctx.save();
  ctx.translate(...pad.pos);
  if(pad.shape !== 'polygon') {
    ctx.rotate(deg2rad(pad.angle));  
  } else {
    ctx.rotate(deg2rad(0));  
  }
  
  if (pad.offset) {
    ctx.translate(...pad.offset);
  }
  ctx.fillStyle = color;
  ctx.strokeStyle = color;
  var path = getCachedPadPath(pad);
  if (outline) {
    ctx.stroke(path);
  } else {
    ctx.fill(path);
  }
  ctx.restore();
}

function drawPadHole(ctx, pad, padHoleColor) {
  if (pad.type != "th") {
    return
  };

  ctx.save();
  ctx.translate(pad.holeCenterPoint.x, pad.holeCenterPoint.y);    
  ctx.rotate(deg2rad(pad.angle));
  ctx.fillStyle = padHoleColor;
  if (pad.drillshape == "oblong") {
    ctx.fill(getOblongPath(pad.drillsize));
  } else {
    ctx.fill(getCirclePath(pad.drillsize[0] / 2));
  }
  ctx.restore();
}

function drawFootprint(ctx, layer, scalefactor, footprint, padColor, padHoleColor, outlineColor, highlight, outline) {
  if (highlight) {
    // draw bounding box
    if (footprint.layer == layer) {
      ctx.save();
      ctx.globalAlpha = 0.2;
      ctx.translate(...footprint.bbox.pos);
      ctx.rotate(deg2rad(-footprint.bbox.angle));
      ctx.translate(...footprint.bbox.relpos);
      ctx.fillStyle = padColor;
      ctx.fillRect(0, 0, ...footprint.bbox.size);
      ctx.globalAlpha = 1;
      ctx.strokeStyle = padColor;
      ctx.strokeRect(0, 0, ...footprint.bbox.size);
      ctx.restore();
    }
  }
  // draw drawings
  for (var drawing of footprint.drawings) {
    if (drawing.layer == layer) {
      drawDrawing(ctx, scalefactor, drawing.drawing, padColor);
    }
  }
  // draw pads
  if (settings.renderPads) {
    for (var pad of footprint.pads) {
      if (pad.layers.includes(layer)) {
        drawPad(ctx, pad, padColor, outline);
        if (pad.pin1 && settings.highlightpin1) {
          drawPad(ctx, pad, outlineColor, true);
        }
      }
    }
    for (var pad of footprint.pads) {
      drawPadHole(ctx, pad, padHoleColor);
    }
  }
}

function drawCrosshair(canvas, x, y, scalefactor, color) {
  if(!settings.showCrosshair) {
    return;
  }

  var ctx = canvas.getContext("2d");

  HTMLFormControlsCollection.log
  
  ctx.save();
  ctx.globalAlpha = 0.75;
  ctx.lineWidth = 2 / scalefactor;
  ctx.strokeStyle = color;

  // TODO: Should calculate a proper bbox for the view port.
  const dummyOffset = 4000;

  // horz line
  ctx.beginPath();
  ctx.moveTo(x - dummyOffset, y);
  ctx.lineTo(x + dummyOffset, y);
  ctx.stroke();

  // vert line
  ctx.beginPath();
  ctx.moveTo(x, y - dummyOffset);
  ctx.lineTo(x, y + dummyOffset);
  ctx.stroke();

  ctx.globalAlpha = 1;
  ctx.restore();
}

function drawEdgeCuts(canvas, scalefactor) {
  var ctx = canvas.getContext("2d");
  var edgecolor = getComputedStyle(topmostdiv).getPropertyValue('--pcb-edge-color');
  for (var edge of pcbdata.edges) {
    drawedge(ctx, scalefactor, edge, edgecolor);
  }
}

function drawOrphanPads(canvas, layer, scalefactor, highlight, highlightedPads) {
  if (!settings.renderPads) {
    return;
  }

  highlightedPads = highlightedPads || [];

  var ctx = canvas.getContext("2d");
  ctx.save();
  ctx.lineWidth = 3 / scalefactor;
  var style = getComputedStyle(topmostdiv);
  var padColor = style.getPropertyValue('--pad-color');
  var padHoleColor = style.getPropertyValue('--pad-hole-color');  
  if (highlight) {
    padColor = style.getPropertyValue('--pad-color-highlight');
    outlineColor = style.getPropertyValue('--pin1-outline-color-highlight');
  }

  var i = 0;
  for (var pad of pcbdata.pads) {
    if (pad.layers.includes(layer)) {
      var outline = settings.renderDnpOutline;
      if (!highlight || highlightedPads.includes(i)) {
        drawPad(ctx, pad, padColor, outline); 
      }     
    }

    i++;
  }
  
  for (var pad of pcbdata.pads) {
    drawPadHole(ctx, pad, padHoleColor);
  }  

  ctx.restore();
}

function drawFootprints(canvas, layer, scalefactor, highlight) {
  var ctx = canvas.getContext("2d");
  ctx.save();
  ctx.lineWidth = 3 / scalefactor;
  var style = getComputedStyle(topmostdiv);
  var padColor = style.getPropertyValue('--pad-color');
  var padHoleColor = style.getPropertyValue('--pad-hole-color');
  var outlineColor = style.getPropertyValue('--pin1-outline-color');
  if (highlight) {
    padColor = style.getPropertyValue('--pad-color-highlight');
    outlineColor = style.getPropertyValue('--pin1-outline-color-highlight');
  }
  for (var i = 0; i < pcbdata.footprints.length; i++) {
    var mod = pcbdata.footprints[i];
    var outline = settings.renderDnpOutline && pcbdata.bom.skipped.includes(i);
    if (!highlight || highlightedFootprints.includes(i)) {
      drawFootprint(ctx, layer, scalefactor, mod, padColor, padHoleColor, outlineColor, highlight, outline);
    }
  }
  ctx.restore();
}

function drawBgLayer(layername, canvas, layer, scalefactor, edgeColor, polygonColor, textColor) {
  var ctx = canvas.getContext("2d");
  for (var d of pcbdata.drawings[layername][layer]) {
    if (["segment", "arc", "circle", "curve", "rect","polyline"].includes(d.type)) {
      drawedge(ctx, scalefactor, d, edgeColor);
    } else if (d.type == "polygon") {
      drawPolygonShape(ctx, d, polygonColor);
    } else if (d.type == "text") {
      drawText(ctx, d, polygonColor);
    }
  }
}

function drawTracks(canvas, layer, color, highlight) {
  ctx = canvas.getContext("2d");
  ctx.strokeStyle = color;
  ctx.lineCap = "round";
  for(var track of pcbdata.tracks[layer]) {
    if (highlight && highlightedNet != track.net) continue;
    ctx.lineWidth = track.width;

    if(track.type === 'polyline') {
      drawPolylineShape(ctx,track,color);
    } else if(track.type === 'polygon') {
      drawPolygonShape(ctx, track, color);
    } else if(track.type === 'text') {
      drawText(ctx, track, color);
    } else {
      if ('radius' in track) {
        ctx.beginPath();
        ctx.arc(
            ...track.center,
            track.radius,
            deg2rad(track.startangle),
            deg2rad(track.endangle));
        ctx.stroke();
      } else if('start' in track && 'end' in track) {
        ctx.beginPath();
        ctx.moveTo(...track.start);
        ctx.lineTo(...track.end);
        ctx.stroke();
      }
      
    }

  }
}

function drawZones(canvas, layer, color, highlight) {
  ctx = canvas.getContext("2d");
  ctx.save();
  ctx.strokeStyle = color;
  ctx.fillStyle = color;
  ctx.lineJoin = "round";
  for(var zone of pcbdata.zones[layer]) {
    if (!zone.path2d) {
      zone.path2d = getPolygonsPath(zone);
    }
    if (highlight && highlightedNet != zone.net) continue;
    ctx.fill(zone.path2d);
    if (zone.width > 0) {
      ctx.lineWidth = zone.width;
      ctx.stroke(zone.path2d);
    }
  }
  ctx.restore();
}

function clearCanvas(canvas, color = null) {
  var ctx = canvas.getContext("2d");
  ctx.save();
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  if (color) {
    ctx.fillStyle = color;
    ctx.fillRect(0, 0, canvas.width, canvas.height);
  } else {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  }
  ctx.restore();
}

function drawNets(canvas, layer, highlight) {
  var style = getComputedStyle(topmostdiv);
  if (settings.renderTracks) {
    var trackColor = style.getPropertyValue(highlight ? '--track-color-highlight' : '--track-color');
    drawTracks(canvas, layer, trackColor, highlight);
  }
  if (settings.renderZones) {
    var zoneColor = style.getPropertyValue(highlight ? '--zone-color-highlight' : '--zone-color');
    drawZones(canvas, layer, zoneColor, highlight);
  }
  if (highlight && settings.renderPads) {
    var padColor = style.getPropertyValue('--pad-color-highlight');
    var padHoleColor = style.getPropertyValue('--pad-hole-color');
    var ctx = canvas.getContext("2d");
    for (var footprint of pcbdata.footprints) {
      // draw pads
      var padDrawn = false;
      for (var pad of footprint.pads) {
        if (highlightedNet != pad.net) continue;
        if (pad.layers.includes(layer)) {
          drawPad(ctx, pad, padColor, false);
          padDrawn = true;
        }
      }
      if (padDrawn) {
        // redraw all pad holes because some pads may overlap
        for (var pad of footprint.pads) {
          drawPadHole(ctx, pad, padHoleColor);
        }
      }
    }
  }
}

function drawHighlightsOnLayer(canvasdict, clear = true) {
  if (clear) {
    clearCanvas(canvasdict.highlight);
  }
  
  if (highlightedFootprints.length > 0) {
    drawFootprints(canvasdict.highlight, canvasdict.layer,
      canvasdict.transform.s * canvasdict.transform.zoom, true);
  }

  // Draw crosshairs
  if (highlightedFootprints.length > 0) {
    for(var i = 0; i < pcbdata.footprints.length; i++) {
      const footprint = pcbdata.footprints[i];
      if(highlightedFootprints.includes(i) && footprint.layer === canvasdict.layer) {
        drawCrosshair(canvasdict.highlight, footprint.center[0], footprint.center[1], canvasdict.transform.s * canvasdict.transform.zoom, 'red');
      }
    }
  }

  if (highlightedNet !== null) {
    var highlightedPads = [];
    for(var i = 0; i < pcbdata.pads.length; i++) {
      var pad = pcbdata.pads[i];
      if(pad.net === highlightedNet) {
        highlightedPads.push(i);
      }
    }
    
    drawOrphanPads(canvasdict.highlight, canvasdict.layer,
      canvasdict.transform.s * canvasdict.transform.zoom, true, highlightedPads);

    drawNets(canvasdict.highlight, canvasdict.layer, true);
  }
}

function drawHighlights() {
  drawHighlightsOnLayer(allcanvas.front);
  drawHighlightsOnLayer(allcanvas.back);
}

function drawBackground(canvasdict, clear = true) {
  if (clear) {
    clearCanvas(canvasdict.bg);
    clearCanvas(canvasdict.fab);
    clearCanvas(canvasdict.silk);
  }

  drawNets(canvasdict.bg, canvasdict.layer, false);

  drawOrphanPads(canvasdict.bg, canvasdict.layer, canvasdict.transform.s * canvasdict.transform.zoom, false);

  drawFootprints(canvasdict.bg, canvasdict.layer, canvasdict.transform.s * canvasdict.transform.zoom, false);

  drawEdgeCuts(canvasdict.bg, canvasdict.transform.s);

  var style = getComputedStyle(topmostdiv);
  var edgeColor = style.getPropertyValue('--silkscreen-edge-color');
  var polygonColor = style.getPropertyValue('--silkscreen-polygon-color');
  var textColor = style.getPropertyValue('--silkscreen-text-color');
  if (settings.renderSilkscreen) {
    drawBgLayer(
      "silkscreen", canvasdict.silk, canvasdict.layer,
      canvasdict.transform.s * canvasdict.transform.zoom,
      edgeColor, polygonColor, textColor);
  }
  edgeColor = style.getPropertyValue('--fabrication-edge-color');
  polygonColor = style.getPropertyValue('--fabrication-polygon-color');
  textColor = style.getPropertyValue('--fabrication-text-color');
  if (settings.renderFabrication) {
    drawBgLayer(
      "fabrication", canvasdict.fab, canvasdict.layer,
      canvasdict.transform.s * canvasdict.transform.zoom,
      edgeColor, polygonColor, textColor);
  }
}

function prepareCanvas(canvas, flip, transform) {
  var ctx = canvas.getContext("2d");
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  var fontsize = 1.55;
  ctx.scale(transform.zoom, transform.zoom);
  ctx.translate(transform.panx, transform.pany);
  if (flip) {
    ctx.scale(-1, 1);
  }
  ctx.translate(transform.x, transform.y);
  ctx.rotate(deg2rad(settings.boardRotation));
  ctx.scale(transform.s, transform.s);
}

function prepareLayer(canvasdict) {
  var flip = (canvasdict.layer == "B");
  for (var c of ["bg", "fab", "silk", "highlight"]) {
    prepareCanvas(canvasdict[c], flip, canvasdict.transform);
  }
}

function rotateVector(v, angle) {
  angle = deg2rad(angle);
  return [
    v[0] * Math.cos(angle) - v[1] * Math.sin(angle),
    v[0] * Math.sin(angle) + v[1] * Math.cos(angle)
  ];
}

function applyRotation(bbox) {
  var corners = [
    [bbox.minx, bbox.miny],
    [bbox.minx, bbox.maxy],
    [bbox.maxx, bbox.miny],
    [bbox.maxx, bbox.maxy],
  ];
  corners = corners.map((v) => rotateVector(v, settings.boardRotation));
  return {
    minx: corners.reduce((a, v) => Math.min(a, v[0]), Infinity),
    miny: corners.reduce((a, v) => Math.min(a, v[1]), Infinity),
    maxx: corners.reduce((a, v) => Math.max(a, v[0]), -Infinity),
    maxy: corners.reduce((a, v) => Math.max(a, v[1]), -Infinity),
  }
}

function recalcLayerScale(layerdict, width, height) {
  var bbox = applyRotation(pcbdata.edges_bbox);
  var scalefactor = 0.98 * Math.min(
    width / (bbox.maxx - bbox.minx),
    height / (bbox.maxy - bbox.miny)
  );
  if (scalefactor < 0.1) {
    scalefactor = 1;
  }
  layerdict.transform.s = scalefactor;
  var flip = (layerdict.layer == "B");
  if (flip) {
    layerdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor + width) * 0.5;
  } else {
    layerdict.transform.x = -((bbox.maxx + bbox.minx) * scalefactor - width) * 0.5;
  }
  layerdict.transform.y = -((bbox.maxy + bbox.miny) * scalefactor - height) * 0.5;
  for (var c of ["bg", "fab", "silk", "highlight"]) {
    canvas = layerdict[c];
    canvas.width = width;
    canvas.height = height;
    canvas.style.width = (width / devicePixelRatio) + "px";
    canvas.style.height = (height / devicePixelRatio) + "px";
  }
}

function redrawCanvas(layerdict) {
  prepareLayer(layerdict);
  drawBackground(layerdict);
  drawHighlightsOnLayer(layerdict);
}

function resizeCanvas(layerdict) {
  var canvasdivid = {
    "F": "frontcanvas",
    "B": "backcanvas"
  } [layerdict.layer];
  var width = document.getElementById(canvasdivid).clientWidth * devicePixelRatio;
  var height = document.getElementById(canvasdivid).clientHeight * devicePixelRatio;
  recalcLayerScale(layerdict, width, height);
  redrawCanvas(layerdict);
}

function resizeAll() {
  resizeCanvas(allcanvas.front);
  resizeCanvas(allcanvas.back);
}

function pointWithinDistanceToSegment(x, y, x1, y1, x2, y2, d) {
  var A = x - x1;
  var B = y - y1;
  var C = x2 - x1;
  var D = y2 - y1;

  var dot = A * C + B * D;
  var len_sq = C * C + D * D;
  var dx, dy;
  if (len_sq == 0) {
    // start and end of the segment coincide
    dx = x - x1;
    dy = y - y1;
  } else {
    var param = dot / len_sq;
    var xx, yy;
    if (param < 0) {
      xx = x1;
      yy = y1;
    } else if (param > 1) {
      xx = x2;
      yy = y2;
    } else {
      xx = x1 + param * C;
      yy = y1 + param * D;
    }
    dx = x - xx;
    dy = y - yy;
  }
  return dx * dx + dy * dy <= d * d;
}

function modulo(n, mod) {
  return ((n % mod) + mod ) % mod;
}

function pointWithinDistanceToArc(x, y, xc, yc, radius, startangle, endangle, d) {
  var dx = x - xc;
  var dy = y - yc;
  var r_sq = dx * dx + dy * dy;
  var rmin = Math.max(0, radius-d);
  var rmax = radius + d;

  if (r_sq < rmin * rmin || r_sq > rmax * rmax)
    return false;

  var angle1 = modulo(deg2rad(startangle), 2 * Math.PI);
  var dx1 = xc + radius * Math.cos(angle1) - x;
  var dy1 = yc + radius * Math.sin(angle1) - y;
  if (dx1 * dx1 + dy1 * dy1 <= d * d)
    return true;

  var angle2 = modulo(deg2rad(endangle), 2 * Math.PI);
  var dx2 = xc + radius * Math.cos(angle2) - x;
  var dy2 = yc + radius * Math.sin(angle2) - y;
  if (dx2 * dx2 + dy2 * dy2 <= d * d)
    return true;

  var angle = modulo(Math.atan2(dy, dx), 2 * Math.PI);
  if (angle1 > angle2)
    return (angle >= angle2 || angle <= angle1);
  else
    return (angle >= angle1 && angle <= angle2);
}

function pointWithinPad(x, y, pad) {
  var v = [x - pad.pos[0], y - pad.pos[1]];
  v = rotateVector(v, -pad.angle);
  if (pad.offset) {
    v[0] -= pad.offset[0];
    v[1] -= pad.offset[1];
  }
  return emptyContext2d.isPointInPath(getCachedPadPath(pad), ...v);
}

function netHitScan(layer, x, y) {
  // TODO: Should be refactored

  // Check track segments
  if (settings.renderTracks && pcbdata.tracks) {
    for(var track of pcbdata.tracks[layer]) {
      if(track.type === 'polyline') {
        const path = getPolygonsPath(track);
        if(path) {
          hitTestContext2d.save();
          hitTestContext2d.lineWidth = track.width;
          
          if(hitTestContext2d.isPointInStroke(path,x,y)) {
            hitTestContext2d.restore();
            return track.net;            
          }
          
          hitTestContext2d.restore();          
        }        

      } else if(track.type === 'polygon') {
        const path = getPolygonsPath(track);
        if(path && hitTestContext2d.isPointInPath(path,x,y)) {          
          return track.net;                      
        }                     
      } else if(track.type === 'text') {
        // TODO: To implement taking in account TrueType fonts.
      } else if ('radius' in track) {
        if (pointWithinDistanceToArc(x, y, ...track.center, track.radius, track.startangle, track.endangle, track.width / 2)) {
          return track.net;
        }
      } else if('start' in track && 'end' in track) {
        if (pointWithinDistanceToSegment(x, y, ...track.start, ...track.end, track.width / 2)) {
          return track.net;
        }
      }
    }
  }
  // Check pads
  if (settings.renderPads) {

    // Footprints containing pads
    for (var footprint of pcbdata.footprints) {
      for(var pad of footprint.pads) {
        if (pad.layers.includes(layer) && pointWithinPad(x, y, pad)) {
          return pad.net;
        }
      }
    }

    // Orphan pads
    for(var pad of pcbdata.pads) {
      if (pad.layers.includes(layer) && pointWithinPad(x, y, pad)) {
        return pad.net;
      }
    }
  }
  return null;
}

function pointWithinFootprintBbox(x, y, bbox) {
  var v = [x - bbox.pos[0], y - bbox.pos[1]];
  v = rotateVector(v, bbox.angle);
  return bbox.relpos[0] <= v[0] && v[0] <= bbox.relpos[0] + bbox.size[0] &&
         bbox.relpos[1] <= v[1] && v[1] <= bbox.relpos[1] + bbox.size[1];
}

function bboxHitScan(layer, x, y) {
  var result = [];
  for (var i = 0; i < pcbdata.footprints.length; i++) {
    var footprint = pcbdata.footprints[i];
    if (footprint.layer == layer) {
      if (pointWithinFootprintBbox(x, y, footprint.bbox)) {
        result.push(i);
      }
    }
  }
  return result;
}

function handlePointerDown(e, layerdict) {
  if (e.button != 0 && e.button != 1) {
    return;
  }
  e.preventDefault();
  e.stopPropagation();

  if (!e.hasOwnProperty("offsetX")) {
    // The polyfill doesn't set this properly
    e.offsetX = e.pageX - e.currentTarget.offsetLeft;
    e.offsetY = e.pageY - e.currentTarget.offsetTop;
  }

  layerdict.pointerStates[e.pointerId] = {
    distanceTravelled: 0,
    lastX: e.offsetX,
    lastY: e.offsetY,
    downTime: Date.now(),
  };
}

function handleMouseClick(e, layerdict) {
  if (!e.hasOwnProperty("offsetX")) {
    // The polyfill doesn't set this properly
    e.offsetX = e.pageX - e.currentTarget.offsetLeft;
    e.offsetY = e.pageY - e.currentTarget.offsetTop;
  }

  var x = e.offsetX;
  var y = e.offsetY;
  var t = layerdict.transform;
  if (layerdict.layer == "B") {
    x = (devicePixelRatio * x / t.zoom - t.panx + t.x) / -t.s;
  } else {
    x = (devicePixelRatio * x / t.zoom - t.panx - t.x) / t.s;
  }
  y = (devicePixelRatio * y / t.zoom - t.y - t.pany) / t.s;
  var v = rotateVector([x, y], -settings.boardRotation);
  if ("nets" in pcbdata) {
    var net = netHitScan(layerdict.layer, ...v);
    if (net !== highlightedNet) {
      netClicked(net);
    }
  }
  if (highlightedNet === null) {
    var footprints = bboxHitScan(layerdict.layer, ...v);
    if (footprints.length > 0) {
      footprintsClicked(footprints);
    }
  }
}

function handlePointerLeave(e, layerdict) {
  e.preventDefault();
  e.stopPropagation();

  if (!settings.redrawOnDrag) {
    redrawCanvas(layerdict);
  }

  delete layerdict.pointerStates[e.pointerId];
}

function resetTransform(layerdict) {
  layerdict.transform.panx = 0;
  layerdict.transform.pany = 0;
  layerdict.transform.zoom = 1;
  redrawCanvas(layerdict);
}

function handlePointerUp(e, layerdict) {
  if (!e.hasOwnProperty("offsetX")) {
    // The polyfill doesn't set this properly
    e.offsetX = e.pageX - e.currentTarget.offsetLeft;
    e.offsetY = e.pageY - e.currentTarget.offsetTop;
  }

  e.preventDefault();
  e.stopPropagation();

  if (e.button == 2) {
    // Reset pan and zoom on right click.
    resetTransform(layerdict);
    layerdict.anotherPointerTapped = false;
    return;
  }

  // We haven't necessarily had a pointermove event since the interaction started, so make sure we update this now
  var ptr = layerdict.pointerStates[e.pointerId];
  ptr.distanceTravelled += Math.abs(e.offsetX - ptr.lastX) + Math.abs(e.offsetY - ptr.lastY);

  if (e.button == 0 && ptr.distanceTravelled < 10 && Date.now() - ptr.downTime <= 500) {
    if (Object.keys(layerdict.pointerStates).length == 1) {
      if (layerdict.anotherPointerTapped) {
        // This is the second pointer coming off of a two-finger tap
        resetTransform(layerdict);
      } else {
        // This is just a regular tap
        handleMouseClick(e, layerdict);
      }
      layerdict.anotherPointerTapped = false;
    } else {
      // This is the first finger coming off of what could become a two-finger tap
      layerdict.anotherPointerTapped = true;
    }
  } else {
    if (!settings.redrawOnDrag) {
      redrawCanvas(layerdict);
    }
    layerdict.anotherPointerTapped = false;
  }

  delete layerdict.pointerStates[e.pointerId];
}

function handlePointerMove(e, layerdict) {
  if (!layerdict.pointerStates.hasOwnProperty(e.pointerId)) {
    return;
  }
  e.preventDefault();
  e.stopPropagation();

  if (!e.hasOwnProperty("offsetX")) {
    // The polyfill doesn't set this properly
    e.offsetX = e.pageX - e.currentTarget.offsetLeft;
    e.offsetY = e.pageY - e.currentTarget.offsetTop;
  }

  var thisPtr = layerdict.pointerStates[e.pointerId];

  var dx = e.offsetX - thisPtr.lastX;
  var dy = e.offsetY - thisPtr.lastY;

  // If this number is low on pointer up, we count the action as a click
  thisPtr.distanceTravelled += Math.abs(dx) + Math.abs(dy);

  if (Object.keys(layerdict.pointerStates).length == 1) {
    // This is a simple drag
    layerdict.transform.panx += devicePixelRatio * dx / layerdict.transform.zoom;
    layerdict.transform.pany += devicePixelRatio * dy / layerdict.transform.zoom;
  } else if (Object.keys(layerdict.pointerStates).length == 2) {
    var otherPtr = Object.values(layerdict.pointerStates).filter((ptr) => ptr != thisPtr)[0];

    var oldDist = Math.sqrt(Math.pow(thisPtr.lastX - otherPtr.lastX, 2) + Math.pow(thisPtr.lastY - otherPtr.lastY, 2));
    var newDist = Math.sqrt(Math.pow(e.offsetX - otherPtr.lastX, 2)     + Math.pow(e.offsetY - otherPtr.lastY, 2));

    var scaleFactor = newDist/oldDist;

    if (scaleFactor != NaN) {
      layerdict.transform.zoom *= scaleFactor;

      var zoomd = (1 - scaleFactor) / layerdict.transform.zoom;
      layerdict.transform.panx += devicePixelRatio * otherPtr.lastX * zoomd;
      layerdict.transform.pany += devicePixelRatio * otherPtr.lastY * zoomd;
    }
  }

  thisPtr.lastX = e.offsetX;
  thisPtr.lastY = e.offsetY;

  if (settings.redrawOnDrag) {
    redrawCanvas(layerdict);
  }
}

function handleMouseWheel(e, layerdict) {
  e.preventDefault();
  e.stopPropagation();
  var t = layerdict.transform;
  var wheeldelta = e.deltaY;
  if (e.deltaMode == 1) {
    // FF only, scroll by lines
    wheeldelta *= 30;
  } else if (e.deltaMode == 2) {
    wheeldelta *= 300;
  }
  var m = Math.pow(1.1, -wheeldelta / 40);
  // Limit amount of zoom per tick.
  if (m > 2) {
    m = 2;
  } else if (m < 0.5) {
    m = 0.5;
  }
  t.zoom *= m;
  var zoomd = (1 - m) / t.zoom;
  t.panx += devicePixelRatio * e.offsetX * zoomd;
  t.pany += devicePixelRatio * e.offsetY * zoomd;
  redrawCanvas(layerdict);
}

function addMouseHandlers(div, layerdict) {
  div.addEventListener("pointerdown", function(e) {
    handlePointerDown(e, layerdict);
  });
  div.addEventListener("pointermove", function(e) {
    handlePointerMove(e, layerdict);
  });
  div.addEventListener("pointerup", function(e) {
    handlePointerUp(e, layerdict);
  });
  var pointerleave = function(e) {
    handlePointerLeave(e, layerdict);
  }
  div.addEventListener("pointercancel", pointerleave);
  div.addEventListener("pointerleave", pointerleave);
  div.addEventListener("pointerout", pointerleave);

  div.onwheel = function(e) {
    handleMouseWheel(e, layerdict);
  }
  for (var element of [div, layerdict.bg, layerdict.fab, layerdict.silk, layerdict.highlight]) {
    element.addEventListener("contextmenu", function(e) {
      e.preventDefault();
    }, false);
  }
}

function setRedrawOnDrag(value) {
  settings.redrawOnDrag = value;
  writeStorage("redrawOnDrag", value);
}

function setShowCrosshair(value) {
  settings.showCrosshair = value;
  writeStorage("showCrosshair", value);
}

function setBoardRotation(value) {
  settings.boardRotation = value * 5;
  writeStorage("boardRotation", settings.boardRotation);
  document.getElementById("rotationDegree").textContent = settings.boardRotation;
  resizeAll();
}

function initRender() {
  allcanvas = {
    front: {
      transform: {
        x: 0,
        y: 0,
        s: 1,
        panx: 0,
        pany: 0,
        zoom: 1,
      },
      pointerStates: {},
      anotherPointerTapped: false,
      bg: document.getElementById("F_bg"),
      fab: document.getElementById("F_fab"),
      silk: document.getElementById("F_slk"),
      highlight: document.getElementById("F_hl"),
      layer: "F",
    },
    back: {
      transform: {
        x: 0,
        y: 0,
        s: 1,
        panx: 0,
        pany: 0,
        zoom: 1,
      },
      pointerStates: {},
      anotherPointerTapped: false,
      bg: document.getElementById("B_bg"),
      fab: document.getElementById("B_fab"),
      silk: document.getElementById("B_slk"),
      highlight: document.getElementById("B_hl"),
      layer: "B",
    }
  };
  addMouseHandlers(document.getElementById("frontcanvas"), allcanvas.front);
  addMouseHandlers(document.getElementById("backcanvas"), allcanvas.back);
}

///////////////////////////////////////////////

///////////////////////////////////////////////
/* DOM manipulation and misc code */

var bomsplit;
var canvassplit;
var initDone = false;
var bomSortFunction = null;
var currentSortColumn = null;
var currentSortOrder = null;
var currentHighlightedRowId;
var highlightHandlers = [];
var footprintIndexToHandler = {};
var netsToHandler = {};
var highlightedFootprints = [];
var highlightedOrphanPads = [];
var highlightedNet = null;
var lastClicked;

function dbg(html) {
  dbgdiv.innerHTML = html;
}

function redrawIfInitDone() {
  if (initDone) {
    redrawCanvas(allcanvas.front);
    redrawCanvas(allcanvas.back);
  }
}

function padsVisible(value) {
  writeStorage("padsVisible", value);
  settings.renderPads = value;
  redrawIfInitDone();
}

function referencesVisible(value) {
  writeStorage("referencesVisible", value);
  settings.renderReferences = value;
  redrawIfInitDone();
}

function valuesVisible(value) {
  writeStorage("valuesVisible", value);
  settings.renderValues = value;
  redrawIfInitDone();
}

function tracksVisible(value) {
  writeStorage("tracksVisible", value);
  settings.renderTracks = value;
  redrawIfInitDone();
}

function zonesVisible(value) {
  writeStorage("zonesVisible", value);
  settings.renderZones = value;
  redrawIfInitDone();
}

function dnpOutline(value) {
  writeStorage("dnpOutline", value);
  settings.renderDnpOutline = value;
  redrawIfInitDone();
}

function setDarkMode(value) {
  if (value) {
    topmostdiv.classList.add("dark");
  } else {
    topmostdiv.classList.remove("dark");
  }
  writeStorage("darkmode", value);
  settings.darkMode = value;
  redrawIfInitDone();
}

function setFullscreen(value) {
  if (value) {
    document.documentElement.requestFullscreen();
  } else {
    document.exitFullscreen();
  }
}

function fabricationVisible(value) {
  writeStorage("fabricationVisible", value);
  settings.renderFabrication = value;
  redrawIfInitDone();
}

function silkscreenVisible(value) {
  writeStorage("silkscreenVisible", value);
  settings.renderSilkscreen = value;
  redrawIfInitDone();
}

function setHighlightPin1(value) {
  writeStorage("highlightpin1", value);
  settings.highlightpin1 = value;
  redrawIfInitDone();
}

function getStoredCheckboxRefs(checkbox) {
  function convert(ref) {
    var intref = parseInt(ref);
    if (isNaN(intref)) {
      for (var i = 0; i < pcbdata.footprints.length; i++) {
        if (pcbdata.footprints[i].ref == ref) {
          return i;
        }
      }
      return -1;
    } else {
      return intref;
    }
  }
  if (!(checkbox in settings.checkboxStoredRefs)) {
    var val = readStorage("checkbox_" + checkbox);
    settings.checkboxStoredRefs[checkbox] = val ? val : "";
  }
  if (!settings.checkboxStoredRefs[checkbox]) {
    return new Set();
  } else {
    return new Set(settings.checkboxStoredRefs[checkbox].split(",").map(r => convert(r)).filter(a => a >= 0));
  }
}

function getCheckboxState(checkbox, references) {
  var storedRefsSet = getStoredCheckboxRefs(checkbox);
  var currentRefsSet = new Set(references.map(r => r[1]));
  // Get difference of current - stored
  var difference = new Set(currentRefsSet);
  for (ref of storedRefsSet) {
    difference.delete(ref);
  }
  if (difference.size == 0) {
    // All the current refs are stored
    return "checked";
  } else if (difference.size == currentRefsSet.size) {
    // None of the current refs are stored
    return "unchecked";
  } else {
    // Some of the refs are stored
    return "indeterminate";
  }
}

function setBomCheckboxState(checkbox, element, references) {
  var state = getCheckboxState(checkbox, references);
  element.checked = (state == "checked");
  element.indeterminate = (state == "indeterminate");
}

function createCheckboxChangeHandler(checkbox, references, row) {
  return function() {
    refsSet = getStoredCheckboxRefs(checkbox);
    var darkenWhenChecked = settings.darkenWhenChecked == checkbox;
    eventArgs = {
      checkbox: checkbox,
      refs: references,
    }
    if (this.checked) {
      // checkbox ticked
      for (var ref of references) {
        refsSet.add(ref[1]);
      }
      if (darkenWhenChecked) {
        row.classList.add("checked");
      }
      eventArgs.state = 'checked';
    } else {
      // checkbox unticked
      for (var ref of references) {
        refsSet.delete(ref[1]);
      }
      if (darkenWhenChecked) {
        row.classList.remove("checked");
      }
      eventArgs.state = 'unchecked';
    }
    settings.checkboxStoredRefs[checkbox] = [...refsSet].join(",");
    writeStorage("checkbox_" + checkbox, settings.checkboxStoredRefs[checkbox]);
    updateCheckboxStats(checkbox);
    EventHandler.emitEvent(IBOM_EVENT_TYPES.CHECKBOX_CHANGE_EVENT, eventArgs);
  }
}

function clearHighlightedFootprints() {
  if (currentHighlightedRowId) {
    document.getElementById(currentHighlightedRowId).classList.remove("highlighted");
    currentHighlightedRowId = null;
    highlightedFootprints = [];  
    highlightedOrphanPads = [];  
    highlightedNet = null;
  }
}

function createRowHighlightHandler(rowid, refs, net) {
  return function() {
    if (currentHighlightedRowId) {
      if (currentHighlightedRowId == rowid) {
        return;
      }
      document.getElementById(currentHighlightedRowId).classList.remove("highlighted");
    }
    document.getElementById(rowid).classList.add("highlighted");
    currentHighlightedRowId = rowid;
    highlightedFootprints = refs ? refs.map(r => r[1]) : [];
    highlightedNet = net;
    drawHighlights();
    EventHandler.emitEvent(
      IBOM_EVENT_TYPES.HIGHLIGHT_EVENT,
      {
        rowid: rowid,
        refs: refs,
        net: net
      });
  }
}

function entryMatches(entry) {
  if (settings.bommode == "netlist") {
    // entry is just a net name
    return entry.toLowerCase().indexOf(filter) >= 0;
  }
  // check refs
  for (var ref of entry[3]) {
    if (ref[0].toLowerCase().indexOf(filter) >= 0) {
      return true;
    }
  }
  // check extra fields
  for (var i in config.extra_fields) {
    if (entry[4][i].toLowerCase().indexOf(filter) >= 0) {
      return true;
    }
  }
  // check value
  if (entry[1].toLowerCase().indexOf(filter) >= 0) {
    return true;
  }
  // check footprint
  if (entry[2].toLowerCase().indexOf(filter) >= 0) {
    return true;
  }
  return false;
}

function findRefInEntry(entry) {
  return entry[3].filter(r => r[0].toLowerCase() == reflookup);
}

function highlightFilter(s) {
  if (!filter) {
    return s;
  }
  var parts = s.toLowerCase().split(filter);
  if (parts.length == 1) {
    return s;
  }
  var r = "";
  var pos = 0;
  for (var i in parts) {
    if (i > 0) {
      r += '<mark class="highlight">' +
        s.substring(pos, pos + filter.length) +
        '</mark>';
      pos += filter.length;
    }
    r += s.substring(pos, pos + parts[i].length);
    pos += parts[i].length;
  }
  return r;
}

function checkboxSetUnsetAllHandler(checkboxname) {
  return function() {
    var checkboxnum = 0;
    while (checkboxnum < settings.checkboxes.length &&
      settings.checkboxes[checkboxnum].toLowerCase() != checkboxname.toLowerCase()) {
      checkboxnum++;
    }
    if (checkboxnum >= settings.checkboxes.length) {
      return;
    }
    var allset = true;
    var checkbox;
    var row;
    for (row of bombody.childNodes) {
      checkbox = row.childNodes[checkboxnum + 1].childNodes[0];
      if (!checkbox.checked || checkbox.indeterminate) {
        allset = false;
        break;
      }
    }
    for (row of bombody.childNodes) {
      checkbox = row.childNodes[checkboxnum + 1].childNodes[0];
      checkbox.checked = !allset;
      checkbox.indeterminate = false;
      checkbox.onchange();
    }
  }
}

function createColumnHeader(name, cls, comparator) {
  var th = document.createElement("TH");
  th.innerHTML = name;
  th.classList.add(cls);
  th.style.cursor = "pointer";
  var span = document.createElement("SPAN");
  span.classList.add("sortmark");
  span.classList.add("none");
  th.appendChild(span);
  th.onclick = function() {
    if (currentSortColumn && this !== currentSortColumn) {
      // Currently sorted by another column
      currentSortColumn.childNodes[1].classList.remove(currentSortOrder);
      currentSortColumn.childNodes[1].classList.add("none");
      currentSortColumn = null;
      currentSortOrder = null;
    }
    if (currentSortColumn && this === currentSortColumn) {
      // Already sorted by this column
      if (currentSortOrder == "asc") {
        // Sort by this column, descending order
        bomSortFunction = function(a, b) {
          return -comparator(a, b);
        }
        currentSortColumn.childNodes[1].classList.remove("asc");
        currentSortColumn.childNodes[1].classList.add("desc");
        currentSortOrder = "desc";
      } else {
        // Unsort
        bomSortFunction = null;
        currentSortColumn.childNodes[1].classList.remove("desc");
        currentSortColumn.childNodes[1].classList.add("none");
        currentSortColumn = null;
        currentSortOrder = null;
      }
    } else {
      // Sort by this column, ascending order
      bomSortFunction = comparator;
      currentSortColumn = this;
      currentSortColumn.childNodes[1].classList.remove("none");
      currentSortColumn.childNodes[1].classList.add("asc");
      currentSortOrder = "asc";
    }
    populateBomBody();
  }
  return th;
}

function populateBomHeader() {
  while (bomhead.firstChild) {
    bomhead.removeChild(bomhead.firstChild);
  }
  var tr = document.createElement("TR");
  var th = document.createElement("TH");
  th.classList.add("numCol");
  tr.appendChild(th);
  var checkboxCompareClosure = function(checkbox) {
    return (a, b) => {
      var stateA = getCheckboxState(checkbox, a[3]);
      var stateB = getCheckboxState(checkbox, b[3]);
      if (stateA > stateB) return -1;
      if (stateA < stateB) return 1;
      return 0;
    }
  }
  if (settings.bommode == "netlist") {
    th = createColumnHeader("Net name", "bom-netname", (a, b) => {
      if (a > b) return -1;
      if (a < b) return 1;
      return 0;
    });
    tr.appendChild(th);
  } else {
    for (var checkbox of settings.checkboxes) {
      th = createColumnHeader(
        checkbox, "bom-checkbox", checkboxCompareClosure(checkbox));
      th.onclick = fancyDblClickHandler(
        th, th.onclick.bind(th), checkboxSetUnsetAllHandler(checkbox));
      tr.appendChild(th);
    }
    tr.appendChild(createColumnHeader("References", "References", (a, b) => {
      var i = 0;
      while (i < a[3].length && i < b[3].length) {
        if (a[3][i] != b[3][i]) return a[3][i] > b[3][i] ? 1 : -1;
        i++;
      }
      return a[3].length - b[3].length;
    }));
    // Extra fields
    if (config.extra_fields.length > 0) {
      var extraFieldCompareClosure = function(fieldIndex) {
        return (a, b) => {
          var fa = a[4][fieldIndex];
          var fb = b[4][fieldIndex];
          if (fa != fb) return fa > fb ? 1 : -1;
          else return 0;
        }
      }
      for (var i in config.extra_fields) {
        tr.appendChild(createColumnHeader(
          config.extra_fields[i], "extra", extraFieldCompareClosure(i)));
      }
    }
    tr.appendChild(createColumnHeader("Value", "Value", (a, b) => {
      return valueCompare(a[5], b[5], a[1], b[1]);
    }));
    tr.appendChild(createColumnHeader("Footprint", "Footprint", (a, b) => {
      if (a[2] != b[2]) return a[2] > b[2] ? 1 : -1;
      else return 0;
    }));
    if (settings.bommode == "grouped") {
      tr.appendChild(createColumnHeader("Quantity", "Quantity", (a, b) => {
        return a[3].length - b[3].length;
      }));
    }
  }
  bomhead.appendChild(tr);
}

function populateBomBody() {
  while (bom.firstChild) {
    bom.removeChild(bom.firstChild);
  }
  highlightHandlers = [];
  footprintIndexToHandler = {};
  netsToHandler = {};
  currentHighlightedRowId = null;
  var first = true;
  if (settings.bommode == "netlist") {
    bomtable = pcbdata.nets.slice();
  } else {
    switch (settings.canvaslayout) {
      case 'F':
        bomtable = pcbdata.bom.F.slice();
        break;
      case 'FB':
        bomtable = pcbdata.bom.both.slice();
        break;
      case 'B':
        bomtable = pcbdata.bom.B.slice();
        break;
    }
    if (settings.bommode == "ungrouped") {
      // expand bom table
      expandedTable = []
      for (var bomentry of bomtable) {
        for (var ref of bomentry[3]) {
          expandedTable.push([1, bomentry[1], bomentry[2], [ref], bomentry[4], bomentry[5]]);
        }
      }
      bomtable = expandedTable;
    }
  }
  if (bomSortFunction) {
    bomtable = bomtable.sort(bomSortFunction);
  }
  for (var i in bomtable) {
    var bomentry = bomtable[i];
    if (filter && !entryMatches(bomentry)) {
      continue;
    }
    var references = null;
    var netname = null;
    var tr = document.createElement("TR");
    var td = document.createElement("TD");
    var rownum = +i + 1;
    tr.id = "bomrow" + rownum;
    td.textContent = rownum;
    tr.appendChild(td);
    if (settings.bommode == "netlist") {
      netname = bomentry;
      td = document.createElement("TD");
      td.innerHTML = highlightFilter(netname ? netname : "&lt;no net&gt;");
      tr.appendChild(td);
    } else {
      if (reflookup) {
        references = findRefInEntry(bomentry);
        if (references.length == 0) {
          continue;
        }
      } else {
        references = bomentry[3];
      }
      // Checkboxes
      for (var checkbox of settings.checkboxes) {
        if (checkbox) {
          td = document.createElement("TD");
          var input = document.createElement("input");
          input.type = "checkbox";
          input.onchange = createCheckboxChangeHandler(checkbox, references, tr);
          setBomCheckboxState(checkbox, input, references);
          if (input.checked && settings.darkenWhenChecked == checkbox) {
            tr.classList.add("checked");
          }
          td.appendChild(input);
          tr.appendChild(td);
        }
      }
      // References
      td = document.createElement("TD");
      td.innerHTML = highlightFilter(references.map(r => r[0]).join(", "));
      tr.appendChild(td);
      // Extra fields
      for (var i in config.extra_fields) {
        td = document.createElement("TD");
        td.innerHTML = highlightFilter(bomentry[4][i]);
        tr.appendChild(td);
      }
      // Value
      td = document.createElement("TD");
      td.innerHTML = highlightFilter(bomentry[1]);
      tr.appendChild(td);
      // Footprint
      td = document.createElement("TD");
      td.innerHTML = highlightFilter(bomentry[2]);
      tr.appendChild(td);
      if (settings.bommode == "grouped") {
        // Quantity
        td = document.createElement("TD");
        td.textContent = bomentry[3].length;
        tr.appendChild(td);
      }
    }
    bom.appendChild(tr);
    var handler = createRowHighlightHandler(tr.id, references, netname);
    tr.onmousemove = handler;
    highlightHandlers.push({
      id: tr.id,
      handler: handler,
    });
    if (references !== null) {
      for (var refIndex of references.map(r => r[1])) {
        footprintIndexToHandler[refIndex] = handler;
      }
    }
    if (netname !== null) {
      netsToHandler[netname] = handler;
    }
    if ((filter || reflookup) && first) {
      handler();
      first = false;
    }
  }
  EventHandler.emitEvent(
    IBOM_EVENT_TYPES.BOM_BODY_CHANGE_EVENT,
    {
      filter: filter,
      reflookup: reflookup,
      checkboxes: settings.checkboxes,
      bommode: settings.bommode,
    });
}

function highlightPreviousRow() {
  if (!currentHighlightedRowId) {
    highlightHandlers[highlightHandlers.length - 1].handler();
  } else {
    if (highlightHandlers.length > 1 &&
      highlightHandlers[0].id == currentHighlightedRowId) {
      highlightHandlers[highlightHandlers.length - 1].handler();
    } else {
      for (var i = 0; i < highlightHandlers.length - 1; i++) {
        if (highlightHandlers[i + 1].id == currentHighlightedRowId) {
          highlightHandlers[i].handler();
          break;
        }
      }
    }
  }
  smoothScrollToRow(currentHighlightedRowId);
}

function highlightNextRow() {
  if (!currentHighlightedRowId) {
    highlightHandlers[0].handler();
  } else {
    if (highlightHandlers.length > 1 &&
      highlightHandlers[highlightHandlers.length - 1].id == currentHighlightedRowId) {
      highlightHandlers[0].handler();
    } else {
      for (var i = 1; i < highlightHandlers.length; i++) {
        if (highlightHandlers[i - 1].id == currentHighlightedRowId) {
          highlightHandlers[i].handler();
          break;
        }
      }
    }
  }
  smoothScrollToRow(currentHighlightedRowId);
}

function populateBomTable() {
  populateBomHeader();
  populateBomBody();
}

function footprintsClicked(footprintIndexes) {
  var lastClickedIndex = footprintIndexes.indexOf(lastClicked);
  for (var i = 1; i <= footprintIndexes.length; i++) {
    var refIndex = footprintIndexes[(lastClickedIndex + i) % footprintIndexes.length];
    if (refIndex in footprintIndexToHandler) {
      lastClicked = refIndex;
      footprintIndexToHandler[refIndex]();
      smoothScrollToRow(currentHighlightedRowId);
      break;
    }
  }
}

function netClicked(net) {
  if (net in netsToHandler) {
    netsToHandler[net]();
    smoothScrollToRow(currentHighlightedRowId);
  } else {
    clearHighlightedFootprints();
    highlightedNet = net;
    drawHighlights();
  }
}

function updateFilter(input) {
  filter = input.toLowerCase();
  populateBomTable();
}

function updateRefLookup(input) {
  reflookup = input.toLowerCase();
  populateBomTable();
}

function changeCanvasLayout(layout) {
  document.getElementById("fl-btn").classList.remove("depressed");
  document.getElementById("fb-btn").classList.remove("depressed");
  document.getElementById("bl-btn").classList.remove("depressed");
  switch (layout) {
    case 'F':
      document.getElementById("fl-btn").classList.add("depressed");
      if (settings.bomlayout != "bom-only") {
        canvassplit.collapse(1);
      }
      break;
    case 'B':
      document.getElementById("bl-btn").classList.add("depressed");
      if (settings.bomlayout != "bom-only") {
        canvassplit.collapse(0);
      }
      break;
    default:
      document.getElementById("fb-btn").classList.add("depressed");
      if (settings.bomlayout != "bom-only") {
        canvassplit.setSizes([50, 50]);
      }
  }
  settings.canvaslayout = layout;
  writeStorage("canvaslayout", layout);
  resizeAll();
  changeBomMode(settings.bommode);
}

function populateMetadata() {
  document.getElementById("title").innerHTML = pcbdata.metadata.title;
  document.getElementById("revision").innerHTML = "Rev: " + pcbdata.metadata.revision;
  document.getElementById("company").innerHTML = pcbdata.metadata.company;
  document.getElementById("filedate").innerHTML = pcbdata.metadata.date;
  if (pcbdata.metadata.title != "") {
    document.title = pcbdata.metadata.title + " BOM";
  }
  // Calculate board stats
  var fp_f = 0, fp_b = 0, pads_f = 0, pads_b = 0, pads_th = 0;
  for (var i = 0; i < pcbdata.footprints.length; i++) {
    if (pcbdata.bom.skipped.includes(i)) continue;
    var mod = pcbdata.footprints[i];
    if (mod.layer == "F") {
      fp_f++;
    } else {
      fp_b++;
    }
    for (var pad of mod.pads) {
      if (pad.type == "th") {
        pads_th++;
      } else {
        if (pad.layers.includes("F")) {
          pads_f++;
        }
        if (pad.layers.includes("B")) {
          pads_b++;
        }
      }
    }
  }
  document.getElementById("stats-components-front").innerHTML = fp_f;
  document.getElementById("stats-components-back").innerHTML = fp_b;
  document.getElementById("stats-components-total").innerHTML = fp_f + fp_b;
  document.getElementById("stats-groups-front").innerHTML = pcbdata.bom.F.length;
  document.getElementById("stats-groups-back").innerHTML = pcbdata.bom.B.length;
  document.getElementById("stats-groups-total").innerHTML = pcbdata.bom.both.length;
  document.getElementById("stats-smd-pads-front").innerHTML = pads_f;
  document.getElementById("stats-smd-pads-back").innerHTML = pads_b;
  document.getElementById("stats-smd-pads-total").innerHTML = pads_f + pads_b;
  document.getElementById("stats-th-pads").innerHTML = pads_th;
  // Update version string
  document.getElementById("github-link").innerHTML = "InteractiveHtmlBom&nbsp;" +
    /^v\d+\.\d+/.exec(pcbdata.ibom_version)[0];
}

function changeBomLayout(layout) {
  document.getElementById("bom-btn").classList.remove("depressed");
  document.getElementById("lr-btn").classList.remove("depressed");
  document.getElementById("tb-btn").classList.remove("depressed");
  switch (layout) {
    case 'bom-only':
      document.getElementById("bom-btn").classList.add("depressed");
      if (bomsplit) {
        bomsplit.destroy();
        bomsplit = null;
        canvassplit.destroy();
        canvassplit = null;
      }
      document.getElementById("frontcanvas").style.display = "none";
      document.getElementById("backcanvas").style.display = "none";
      document.getElementById("bot").style.height = "";
      break;
    case 'top-bottom':
      document.getElementById("tb-btn").classList.add("depressed");
      document.getElementById("frontcanvas").style.display = "";
      document.getElementById("backcanvas").style.display = "";
      document.getElementById("bot").style.height = "calc(100% - 80px)";
      document.getElementById("bomdiv").classList.remove("split-horizontal");
      document.getElementById("canvasdiv").classList.remove("split-horizontal");
      document.getElementById("frontcanvas").classList.add("split-horizontal");
      document.getElementById("backcanvas").classList.add("split-horizontal");
      if (bomsplit) {
        bomsplit.destroy();
        bomsplit = null;
        canvassplit.destroy();
        canvassplit = null;
      }
      bomsplit = Split(['#bomdiv', '#canvasdiv'], {
        sizes: [50, 50],
        onDragEnd: resizeAll,
        direction: "vertical",
        gutterSize: 5
      });
      canvassplit = Split(['#frontcanvas', '#backcanvas'], {
        sizes: [50, 50],
        gutterSize: 5,
        onDragEnd: resizeAll
      });
      break;
    case 'left-right':
      document.getElementById("lr-btn").classList.add("depressed");
      document.getElementById("frontcanvas").style.display = "";
      document.getElementById("backcanvas").style.display = "";
      document.getElementById("bot").style.height = "calc(100% - 80px)";
      document.getElementById("bomdiv").classList.add("split-horizontal");
      document.getElementById("canvasdiv").classList.add("split-horizontal");
      document.getElementById("frontcanvas").classList.remove("split-horizontal");
      document.getElementById("backcanvas").classList.remove("split-horizontal");
      if (bomsplit) {
        bomsplit.destroy();
        bomsplit = null;
        canvassplit.destroy();
        canvassplit = null;
      }
      bomsplit = Split(['#bomdiv', '#canvasdiv'], {
        sizes: [50, 50],
        onDragEnd: resizeAll,
        gutterSize: 5
      });
      canvassplit = Split(['#frontcanvas', '#backcanvas'], {
        sizes: [50, 50],
        gutterSize: 5,
        direction: "vertical",
        onDragEnd: resizeAll
      });
  }
  settings.bomlayout = layout;
  writeStorage("bomlayout", layout);
  changeCanvasLayout(settings.canvaslayout);
}

function changeBomMode(mode) {
  document.getElementById("bom-grouped-btn").classList.remove("depressed");
  document.getElementById("bom-ungrouped-btn").classList.remove("depressed");
  document.getElementById("bom-netlist-btn").classList.remove("depressed");
  switch (mode) {
    case 'grouped':
      document.getElementById("bom-grouped-btn").classList.add("depressed");
      break;
    case 'ungrouped':
      document.getElementById("bom-ungrouped-btn").classList.add("depressed");
      break;
    case 'netlist':
      document.getElementById("bom-netlist-btn").classList.add("depressed");
  }
  writeStorage("bommode", mode);
  if (mode != settings.bommode) {
    settings.bommode = mode;
    bomSortFunction = null;
    currentSortColumn = null;
    currentSortOrder = null;
    clearHighlightedFootprints();
  }
  populateBomTable();
}

function focusFilterField() {
  focusInputField(document.getElementById("filter"));
}

function focusRefLookupField() {
  focusInputField(document.getElementById("reflookup"));
}

function toggleBomCheckbox(bomrowid, checkboxnum) {
  if (!bomrowid || checkboxnum > settings.checkboxes.length) {
    return;
  }
  var bomrow = document.getElementById(bomrowid);
  var checkbox = bomrow.childNodes[checkboxnum].childNodes[0];
  checkbox.checked = !checkbox.checked;
  checkbox.indeterminate = false;
  checkbox.onchange();
}

function checkBomCheckbox(bomrowid, checkboxname) {
  var checkboxnum = 0;
  while (checkboxnum < settings.checkboxes.length &&
    settings.checkboxes[checkboxnum].toLowerCase() != checkboxname.toLowerCase()) {
    checkboxnum++;
  }
  if (!bomrowid || checkboxnum >= settings.checkboxes.length) {
    return;
  }
  var bomrow = document.getElementById(bomrowid);
  var checkbox = bomrow.childNodes[checkboxnum + 1].childNodes[0];
  checkbox.checked = true;
  checkbox.indeterminate = false;
  checkbox.onchange();
}

function setBomCheckboxes(value) {
  writeStorage("bomCheckboxes", value);
  settings.checkboxes = value.split(",").filter((e) => e);
  prepCheckboxes();
  populateBomTable();
  populateDarkenWhenCheckedOptions();
}

function setDarkenWhenChecked(value) {
  writeStorage("darkenWhenChecked", value);
  settings.darkenWhenChecked = value;
  populateBomTable();
}

function prepCheckboxes() {
  var table = document.getElementById("checkbox-stats");
  while (table.childElementCount > 1) {
    table.removeChild(table.lastChild);
  }
  if (settings.checkboxes.length) {
    table.style.display = "";
  } else {
    table.style.display = "none";
  }
  for (var checkbox of settings.checkboxes) {
    var tr = document.createElement("TR");
    var td = document.createElement("TD");
    td.innerHTML = checkbox;
    tr.appendChild(td);
    td = document.createElement("TD");
    td.id = "checkbox-stats-" + checkbox;
    var progressbar = document.createElement("div");
    progressbar.classList.add("bar");
    td.appendChild(progressbar);
    var text = document.createElement("div");
    text.classList.add("text");
    td.appendChild(text);
    tr.appendChild(td);
    table.appendChild(tr);
    updateCheckboxStats(checkbox);
  }
}

function populateDarkenWhenCheckedOptions() {
  var container = document.getElementById("darkenWhenCheckedContainer");

  if (settings.checkboxes.length == 0) {
    container.parentElement.style.display = "none";
    return;
  }

  container.innerHTML = '';
  container.parentElement.style.display = "inline-block";

  function createOption(name, displayName) {
    var id = "darkenWhenChecked-" + name;

    var div = document.createElement("div");
    div.classList.add("radio-container");

    var input = document.createElement("input");
    input.type = "radio";
    input.name = "darkenWhenChecked";
    input.value = name;
    input.id = id;
    input.onchange = () => setDarkenWhenChecked(name);
    div.appendChild(input);

    // Preserve the selected element when the checkboxes change
    if (name == settings.darkenWhenChecked) {
      input.checked = true;
    }

    var label = document.createElement("label");
    label.innerHTML = displayName;
    label.htmlFor = id;
    div.appendChild(label);

    container.appendChild(div);
  }
  createOption("", "None");
  for (var checkbox of settings.checkboxes) {
    createOption(checkbox, checkbox);
  }
}

function updateCheckboxStats(checkbox) {
  var checked = getStoredCheckboxRefs(checkbox).size;
  var total = pcbdata.footprints.length - pcbdata.bom.skipped.length;
  var percent = checked * 100.0 / total;
  var td = document.getElementById("checkbox-stats-" + checkbox);
  td.firstChild.style.width = percent + "%";
  td.lastChild.innerHTML = checked + "/" + total + " (" + Math.round(percent) + "%)";
}

document.onkeydown = function(e) {
  switch (e.key) {
    case "n":
      if (document.activeElement.type == "text") {
        return;
      }
      if (currentHighlightedRowId !== null) {
        checkBomCheckbox(currentHighlightedRowId, "placed");
        highlightNextRow();
        e.preventDefault();
      }
      break;
    case "ArrowUp":
      highlightPreviousRow();
      e.preventDefault();
      break;
    case "ArrowDown":
      highlightNextRow();
      e.preventDefault();
      break;
    default:
      break;
  }
  if (e.altKey) {
    switch (e.key) {
      case "f":
        focusFilterField();
        e.preventDefault();
        break;
      case "r":
        focusRefLookupField();
        e.preventDefault();
        break;
      case "z":
        changeBomLayout("bom-only");
        e.preventDefault();
        break;
      case "x":
        changeBomLayout("left-right");
        e.preventDefault();
        break;
      case "c":
        changeBomLayout("top-bottom");
        e.preventDefault();
        break;
      case "v":
        changeCanvasLayout("F");
        e.preventDefault();
        break;
      case "b":
        changeCanvasLayout("FB");
        e.preventDefault();
        break;
      case "n":
        changeCanvasLayout("B");
        e.preventDefault();
        break;
      default:
        break;
    }
    if (e.key >= '1' && e.key <= '9') {
      toggleBomCheckbox(currentHighlightedRowId, parseInt(e.key));
    }
  }
}

function hideNetlistButton() {
  document.getElementById("bom-ungrouped-btn").classList.remove("middle-button");
  document.getElementById("bom-ungrouped-btn").classList.add("right-most-button");
  document.getElementById("bom-netlist-btn").style.display = "none";
}

window.onload = function(e) {
  initUtils();
  initRender();
  initStorage();
  initDefaults();
  cleanGutters();
  populateMetadata();
  dbgdiv = document.getElementById("dbg");
  bom = document.getElementById("bombody");
  bomhead = document.getElementById("bomhead");
  filter = "";
  reflookup = "";
  if (!("nets" in pcbdata)) {
    hideNetlistButton();
  }
  initDone = true;
  prepCheckboxes();
  // Triggers render
  changeBomLayout(settings.bomlayout);

  // Users may leave fullscreen without touching the checkbox. Uncheck.
  document.addEventListener('fullscreenchange', () => {
    if (!document.fullscreenElement)
      document.getElementById('fullscreenCheckbox').checked = false;
  });
}

window.onresize = resizeAll;
window.matchMedia("print").addListener(resizeAll);

///////////////////////////////////////////////

///////////////////////////////////////////////
 
///////////////////////////////////////////////
  </script>
</head>

<body>
<!-- USERHEADER -->
<div id="topmostdiv" class="topmostdiv">
  <div id="top">
    <div style="float: right; height: 100%;">
      <div class="hideonprint menu" style="float: right; top: 8px;">
        <button class="menubtn"></button>
        <div class="menu-content">
          <label class="menu-label menu-label-top" style="width: calc(50% - 18px)">
            <input id="darkmodeCheckbox" type="checkbox" onchange="setDarkMode(this.checked)">
            Dark mode
          </label><!-- This comment eats space! All of it!
          --><label class="menu-label menu-label-top" style="width: calc(50% - 17px); border-left: 0;">
            <input id="fullscreenCheckbox" type="checkbox" onchange="setFullscreen(this.checked)">
            Full Screen
          </label>
          <label class="menu-label" style="width: calc(50% - 18px)">
            <input id="fabricationCheckbox" type="checkbox" checked onchange="fabricationVisible(this.checked)">
            Fab layer
          </label><!-- This comment eats space! All of it!
          --><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
            <input id="silkscreenCheckbox" type="checkbox" checked onchange="silkscreenVisible(this.checked)">
            Silkscreen
          </label>
          <label class="menu-label" style="width: calc(50% - 18px)">
            <input id="referencesCheckbox" type="checkbox" checked onchange="referencesVisible(this.checked)">
            References
          </label><!-- This comment eats space! All of it!
          --><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
            <input id="valuesCheckbox" type="checkbox" checked onchange="valuesVisible(this.checked)">
            Values
          </label>
          <div id="tracksAndZonesCheckboxes">
            <label class="menu-label" style="width: calc(50% - 18px)">
              <input id="tracksCheckbox" type="checkbox" checked onchange="tracksVisible(this.checked)">
              Tracks
            </label><!-- This comment eats space! All of it!
            --><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
              <input id="zonesCheckbox" type="checkbox" checked onchange="zonesVisible(this.checked)">
              Zones
            </label>
          </div>
          <label class="menu-label" style="width: calc(50% - 18px)">
            <input id="padsCheckbox" type="checkbox" checked onchange="padsVisible(this.checked)">
            Pads
          </label><!-- This comment eats space! All of it!
          --><label class="menu-label" style="width: calc(50% - 17px); border-left: 0;">
            <input id="dnpOutlineCheckbox" type="checkbox" checked onchange="dnpOutline(this.checked)">
            DNP outlined
          </label>
          <label class="menu-label">
            <input id="highlightpin1Checkbox" type="checkbox" onchange="setHighlightPin1(this.checked)">
            Highlight first pin
          </label>
          <label class="menu-label">
            <input id="dragCheckbox" type="checkbox" checked onchange="setRedrawOnDrag(this.checked)">
            Continuous redraw on drag
          </label>
          <label class="menu-label">
            <input id="crosshairCheckbox" type="checkbox" checked onchange="setShowCrosshair(this.checked)">
            Show Crosshair
          </label>
          <label class="menu-label">
            <span>Board rotation</span>
            <span style="float: right"><span id="rotationDegree">0</span>&#176;</span>
            <input id="boardRotation" type="range" min="-36" max="36" value="0" class="slider" oninput="setBoardRotation(this.value)">
          </label>
          <label class="menu-label">
            <div style="margin-left: 5px">Bom checkboxes</div>
            <input id="bomCheckboxes" class="menu-textbox" type=text
                   oninput="setBomCheckboxes(this.value)">
          </label>
          <label class="menu-label">
            <div style="margin-left: 5px">Darken when checked</div>
            <div id="darkenWhenCheckedContainer"></div>
          </label>
          <label class="menu-label">
            <span class="shameless-plug">
              <span>Created using</span>
              <a id="github-link" target="blank" href="https://github.com/openscopeproject/InteractiveHtmlBom">InteractiveHtmlBom</a>
            </span>
          </label>
        </div>
      </div>
      <div class="button-container hideonprint"
           style="float: right; position: relative; top: 8px">
        <button id="fl-btn" class="left-most-button" onclick="changeCanvasLayout('F')"
                title="Front only">F
        </button>
        <button id="fb-btn" class="middle-button" onclick="changeCanvasLayout('FB')"
                title="Front and Back">FB
        </button>
        <button id="bl-btn" class="right-most-button" onclick="changeCanvasLayout('B')"
                title="Back only">B
        </button>
      </div>
      <div class="button-container hideonprint"
           style="float: right; position: relative; top: 8px">
        <button id="bom-btn" class="left-most-button" onclick="changeBomLayout('bom-only')"
                title="BOM only"></button>
        <button id="lr-btn" class="middle-button" onclick="changeBomLayout('left-right')"
                title="BOM left, drawings right"></button>
        <button id="tb-btn" class="right-most-button" onclick="changeBomLayout('top-bottom')"
                title="BOM top, drawings bot"></button>
      </div>
      <div class="button-container hideonprint"
           style="float: right; position: relative; top: 8px">
        <button id="bom-grouped-btn" class="left-most-button" onclick="changeBomMode('grouped')"
                title="Grouped BOM"></button>
        <button id="bom-ungrouped-btn" class="middle-button" onclick="changeBomMode('ungrouped')"
                title="Ungrouped BOM"></button>
        <button id="bom-netlist-btn" class="right-most-button" onclick="changeBomMode('netlist')"
                title="Netlist"></button>
      </div>
      <div class="hideonprint menu" style="float: right; top: 8px;">
        <button class="statsbtn"></button>
        <div class="menu-content">
          <table class="stats">
            <tbody>
              <tr>
                <td width="40%">Board stats</td>
                <td>Front</td>
                <td>Back</td>
                <td>Total</td>
              </tr>
              <tr>
                <td>Components</td>
                <td id="stats-components-front">~</td>
                <td id="stats-components-back">~</td>
                <td id="stats-components-total">~</td>
              </tr>
              <tr>
                <td>Groups</td>
                <td id="stats-groups-front">~</td>
                <td id="stats-groups-back">~</td>
                <td id="stats-groups-total">~</td>
              </tr>
              <tr>
                <td>SMD pads</td>
                <td id="stats-smd-pads-front">~</td>
                <td id="stats-smd-pads-back">~</td>
                <td id="stats-smd-pads-total">~</td>
              </tr>
              <tr>
                <td>TH pads</td>
                <td colspan=3 id="stats-th-pads">~</td>
              </tr>
            </tbody>
          </table>
          <table class="stats">
            <col width="40%"/><col />
            <tbody id="checkbox-stats">
              <tr>
                <td colspan=2 style="border-top: 0">Checkboxes</td>
              </tr>
            </tbody>
          </table>
        </div>
      </div>
      <div class="hideonprint menu" style="float: right; top: 8px;">
        <button class="iobtn"></button>
        <div class="menu-content">
          <div class="menu-label menu-label-top">
            <div style="margin-left: 5px;">Save board image</div>
            <div class="flexbox">
              <input id="render-save-width" class="menu-textbox" type="text" value="1000" placeholder="Width"
                  style="flex-grow: 1; width: 50px;" oninput="validateSaveImgDimension(this)">
              <span>X</span>
              <input id="render-save-height" class="menu-textbox" type="text" value="1000" placeholder="Height"
                  style="flex-grow: 1; width: 50px;" oninput="validateSaveImgDimension(this)">
            </div>
            <label>
              <input id="render-save-transparent" type="checkbox">
              Transparent background
            </label>
            <div class="flexbox">
              <button class="savebtn" onclick="saveImage('F')">Front</button>
              <button class="savebtn" onclick="saveImage('B')">Back</button>
            </div>
          </div>
          <div class="menu-label">
            <span style="margin-left: 5px;">Config and checkbox state</span>
            <div class="flexbox">
              <button class="savebtn" onclick="saveSettings()">Export</button>
              <button class="savebtn" onclick="loadSettings()">Import</button>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div id="fileinfodiv" style="overflow: auto;">
      <table class="fileinfo">
        <tbody>
          <tr>
            <td id="title" class="title" style="width: 70%">
              Title
            </td>
            <td id="revision" class="title" style="width: 30%">
              Revision
            </td>
          </tr>
          <tr>
            <td id="company">
              Company
            </td>
            <td id="filedate">
              Date
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
  <div id="bot" class="split" style="height: calc(100% - 80px)">
    <div id="bomdiv" class="split split-horizontal">
      <div style="width: 100%">
        <input id="reflookup" class="textbox searchbox reflookup hideonprint" type="text" placeholder="Ref lookup"
               oninput="updateRefLookup(this.value)">
        <input id="filter" class="textbox searchbox filter hideonprint" type="text" placeholder="Filter"
               oninput="updateFilter(this.value)">
        <div class="button-container hideonprint" style="float: left; margin: 0;">
          <button id="copy" title="Copy bom table to clipboard"
               onclick="copyToClipboard()"></button>
        </div>
      </div>
      <div id="dbg"></div>
      <table class="bom">
        <thead id="bomhead">
        </thead>
        <tbody id="bombody">
        </tbody>
      </table>
    </div>
    <div id="canvasdiv" class="split split-horizontal">
      <div id="frontcanvas" class="split" touch-action="none" style="overflow: hidden">
        <div style="position: relative; width: 100%; height: 100%;">
          <canvas id="F_bg" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
          <canvas id="F_fab" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
          <canvas id="F_slk" style="position: absolute; left: 0; top: 0; z-index: 2;"></canvas>
          <canvas id="F_hl" style="position: absolute; left: 0; top: 0; z-index: 3;"></canvas>
        </div>
      </div>
      <div id="backcanvas" class="split" touch-action="none" style="overflow: hidden">
        <div style="position: relative; width: 100%; height: 100%;">
          <canvas id="B_bg" style="position: absolute; left: 0; top: 0; z-index: 0;"></canvas>
          <canvas id="B_fab" style="position: absolute; left: 0; top: 0; z-index: 1;"></canvas>
          <canvas id="B_slk" style="position: absolute; left: 0; top: 0; z-index: 2;"></canvas>
          <canvas id="B_hl" style="position: absolute; left: 0; top: 0; z-index: 3;"></canvas>
        </div>
      </div>
    </div>
  </div>
</div>
<!-- USERFOOTER -->
</body>

</html>
